/* * * * Copyright 2013 Jive Software * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package com.jivesoftware.sdk.service.oauth; import com.jivesoftware.sdk.config.oauth.JiveOAuth2ServiceConfig; import com.jivesoftware.sdk.event.OAuthEvent; import com.jivesoftware.sdk.event.OAuthEventPublisher; import com.jivesoftware.sdk.utils.JiveSDKUtils; import org.glassfish.jersey.client.oauth2.ClientIdentifier; import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport; import org.glassfish.jersey.client.oauth2.OAuth2CodeGrantFlow; import org.glassfish.jersey.client.oauth2.TokenResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import javax.inject.Singleton; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; /** * Created by rrutan on 1/29/14. */ @Component @Path("/oauth2") @Singleton public class JiveOAuth2Service extends BaseOAuthService { private static final Logger log = LoggerFactory.getLogger(JiveOAuth2Service.class); private static final String SERVICE_NAME = "jive"; @Autowired private JiveOAuth2ServiceConfig serviceConfig; @Override public String getOAuthServiceName() { return SERVICE_NAME; } @Override public int getOAuthVersion() { return 2; } @Autowired @Qualifier("oauthEventPublisher") private OAuthEventPublisher oAuthEventPublisher; @GET @Path("/authorize") public Response authorize(@Context HttpServletRequest request, @Context UriInfo uriInfo) { String userID = "TODO"; //TODO: HEADER/QUERY - PARAM String instanceID = "TODO"; //TODO: HEADER/QUERY - PARAM ClientIdentifier clientID = new ClientIdentifier(serviceConfig.getClientID(),serviceConfig.getClientSecret()); OAuth2CodeGrantFlow flow = OAuth2ClientSupport.authorizationCodeGrantFlowBuilder( clientID, serviceConfig.getAuthorizeUrl(), serviceConfig.getTokenUrl() ).scope(serviceConfig.getScope()) .redirectUri(uriInfo.getBaseUri() + "oauth2/callback") .build(); String authorizationUrl = flow.start(); try { URI authorizationUri = new URI(authorizationUrl); /** LOAD INTO SESSION FOR FOLLOW-UP HIT **/ request.getSession().setAttribute(getFlowSessionKey(),flow); request.getSession().setAttribute(getInstanceIDSessionKey(),instanceID); request.getSession().setAttribute(getUserIDSessionKey(),userID); //*** NOTE: 303 "See Other" NEEDED FOR JERSEY FLOW TO PICK UP return Response.seeOther(new URI(authorizationUrl)).build(); } catch (URISyntaxException use) { log.error("Invalid Authorization URI: "+authorizationUrl); return Response.serverError().entity("Unable to Process this Request").build(); } // end try/catch } // end authorize @GET @Path("/callback") public Response callback(@Context HttpServletRequest request, @Context UriInfo uriInfo, @QueryParam("code") String code, @QueryParam("state") String state) { if (code == null) { if (log.isWarnEnabled()) { log.warn("Authorization Code is null, failed oauth2 callback"); } return Response.status(Response.Status.BAD_REQUEST).entity("Authorization code required").build(); } // end if if (state == null) { if (log.isWarnEnabled()) { log.warn("State is null, failed oauth2 callback"); } return Response.status(Response.Status.BAD_REQUEST).entity("Missing state string").build(); } // end if /*** RETRIEVE FROM SESSION TO CLOSE OUT THE FLOW ***/ OAuth2CodeGrantFlow flow = (OAuth2CodeGrantFlow)request.getSession().getAttribute(getFlowSessionKey()); String instanceID = (String)request.getSession().getAttribute(getInstanceIDSessionKey()); String userID = (String)request.getSession().getAttribute(getUserIDSessionKey()); if (JiveSDKUtils.isAllExist(instanceID, userID, flow)) { TokenResult tokenResult = flow.finish(code,state); if (log.isDebugEnabled()) { log.debug("Successfully Retrieved OAuth Tokens["+SERVICE_NAME+"]: instanceID="+instanceID+", code="+code+", result="+tokenResult); } fireOAuthEvent(OAuthEvent.Type.GrantSuccess,getOAuth2GrantSuccessData(instanceID, userID, code, tokenResult)); try { URI uri = new URI("/oauth/"+SERVICE_NAME+"/callback-close.jsp"); return Response.temporaryRedirect(uri).build(); } catch (URISyntaxException use) { log.error("Invalid Authorization URI: /oauth/"+SERVICE_NAME+"/callback-close.jsp",use); return Response.serverError().entity("Invalid Close URL").build(); } // end try/catch } else { if (log.isWarnEnabled()) { log.warn("Missing Required Data instanceID["+instanceID+"], userID["+userID+"]"); } } // end if return Response.status(404).entity("Resource Not Found").build(); } // end callback @GET @Path("/deauthorize") public Response deauthorize(@Context HttpServletRequest request, @Context UriInfo uriInfo) { if (log.isDebugEnabled()) { log.debug("deauthorize called"); } return Response.status(200).entity("Unimplemented").build(); } // end deauthorize /****************************************************************************************************** * EVENT FIRING * * ******************************************************************************************************/ private void fireOAuthEvent(OAuthEvent.Type type, Map<String, Object> data) { oAuthEventPublisher.publishEvent(new OAuthEvent(type, data)); } // end fireOAuthEvent } // end class JiveOAuth2Service