/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.usergrid.rest.applications;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.usergrid.rest.security.annotations.CheckPermissionsForPath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.apache.usergrid.persistence.entities.User;
import org.apache.usergrid.rest.AbstractContextResource;
import org.apache.usergrid.security.oauth.AccessInfo;
import org.apache.usergrid.security.providers.PingIdentityProvider;
import org.apache.usergrid.security.providers.SignInAsProvider;
import org.apache.usergrid.security.providers.SignInProviderFactory;
import org.apache.usergrid.services.ServiceManager;
import org.apache.amber.oauth2.common.error.OAuthError;
import org.apache.amber.oauth2.common.message.OAuthResponse;
import org.apache.commons.lang.StringUtils;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static org.apache.usergrid.rest.utils.JSONPUtils.jsonMediaType;
import static org.apache.usergrid.rest.utils.JSONPUtils.wrapJSONPResponse;
import static org.apache.usergrid.rest.utils.JSONPUtils.wrapWithCallback;
@Component
@Scope("prototype")
@Produces({
MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript",
"application/ecmascript", "text/jscript"
})
public class AuthResource extends AbstractContextResource {
private static final Logger logger = LoggerFactory.getLogger( AuthResource.class );
ServiceManager services = null;
@Autowired
private SignInProviderFactory signInProviderFactory;
public AuthResource() {
}
@Override
public void setParent( AbstractContextResource parent ) {
super.setParent( parent );
if ( parent instanceof ServiceResource ) {
services = ( ( ServiceResource ) parent ).services;
}
}
@CheckPermissionsForPath
@POST
@Path("facebook")
@Consumes(APPLICATION_FORM_URLENCODED)
public Response authFBPost( @Context UriInfo ui, @FormParam("fb_access_token") String fb_access_token,
@QueryParam("ttl") long ttl, @QueryParam("callback") @DefaultValue("") String callback )
throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("AuthResource.authFBPost");
}
return authFB( ui, fb_access_token, ttl, callback );
}
@CheckPermissionsForPath
@GET
@Path("pingident")
public Response authPingIdent( @Context UriInfo ui, @QueryParam("ping_access_token") String pingToken,
@QueryParam("callback") @DefaultValue("") String callback ) throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("AuthResource.pingIdent");
}
try {
if ( StringUtils.isEmpty( pingToken ) ) {
missingTokenFail( callback );
}
SignInAsProvider pingProvider = signInProviderFactory.pingident( services.getApplication() );
User user = pingProvider.createOrAuthenticate( pingToken );
if ( user == null ) {
return findAndCreateFail( callback );
}
long ttl = PingIdentityProvider.extractExpiration( user );
String token = management.getAccessTokenForAppUser( services.getApplicationId(), user.getUuid(), ttl );
AccessInfo access_info =
new AccessInfo().withExpiresIn( tokens.getMaxTokenAgeInSeconds( token ) ).withAccessToken( token )
.withProperty( "user", user );
return Response.status( SC_OK ).type( jsonMediaType( callback ) )
.entity( wrapWithCallback( access_info, callback ) ).build();
}
catch ( Exception e ) {
return generalAuthError( callback, e );
}
}
@CheckPermissionsForPath
@POST
@Path("pingident")
public Response authPingIdentPost( @Context UriInfo ui, @QueryParam("ping_access_token") String pingToken,
@QueryParam("callback") @DefaultValue("") String callback ) throws Exception {
return authPingIdent( ui, pingToken, callback );
}
private Response missingTokenFail( String callback ) throws Exception {
logger.error( "Missing Access token" );
OAuthResponse response =
OAuthResponse.errorResponse( SC_BAD_REQUEST ).setError( OAuthError.TokenResponse.INVALID_REQUEST )
.setErrorDescription( "missing access token" ).buildJSONMessage();
return Response.status( response.getResponseStatus() ).type( jsonMediaType( callback ) )
.entity( wrapJSONPResponse( callback, response.getBody() ) ).build();
}
private Response findAndCreateFail( String callback ) throws Exception {
logger.error( "Unable to find or create user" );
OAuthResponse response =
OAuthResponse.errorResponse( SC_BAD_REQUEST ).setError( OAuthError.TokenResponse.INVALID_REQUEST )
.setErrorDescription( "invalid user" ).buildJSONMessage();
return Response.status( response.getResponseStatus() ).type( jsonMediaType( callback ) )
.entity( wrapJSONPResponse( callback, response.getBody() ) ).build();
}
private Response generalAuthError( String callback, Exception e ) throws Exception {
logger.error( "Generic Auth Error", e );
OAuthResponse response =
OAuthResponse.errorResponse( SC_BAD_REQUEST ).setError( OAuthError.TokenResponse.INVALID_REQUEST )
.buildJSONMessage();
return Response.status( response.getResponseStatus() ).type( jsonMediaType( callback ) )
.entity( wrapJSONPResponse( callback, response.getBody() ) ).build();
}
@CheckPermissionsForPath
@GET
@Path("facebook")
public Response authFB( @Context UriInfo ui, @QueryParam("fb_access_token") String fb_access_token,
@QueryParam("ttl") long ttl, @QueryParam("callback") @DefaultValue("") String callback )
throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("AuthResource.authFB");
}
try {
if ( StringUtils.isEmpty( fb_access_token ) ) {
return missingTokenFail( callback );
}
SignInAsProvider facebookProvider = signInProviderFactory.facebook( services.getApplication() );
User user = facebookProvider.createOrAuthenticate( fb_access_token );
if ( user == null ) {
return findAndCreateFail( callback );
}
String token = management.getAccessTokenForAppUser( services.getApplicationId(), user.getUuid(), ttl );
AccessInfo access_info =
new AccessInfo().withExpiresIn( tokens.getMaxTokenAgeInSeconds( token ) ).withAccessToken( token )
.withProperty( "user", user );
return Response.status( SC_OK ).type( jsonMediaType( callback ) )
.entity( wrapWithCallback( access_info, callback ) ).build();
}
catch ( Exception e ) {
return generalAuthError( callback, e );
}
}
@CheckPermissionsForPath
@POST
@Path("foursquare")
@Consumes(APPLICATION_FORM_URLENCODED)
public Response authFQPost( @Context UriInfo ui, @FormParam("fq_access_token") String fq_access_token,
@QueryParam("ttl") long ttl, @QueryParam("callback") @DefaultValue("") String callback )
throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("AuthResource.authFQPost");
}
return authFQ( ui, fq_access_token, ttl, callback );
}
@CheckPermissionsForPath
@GET
@Path("foursquare")
public Response authFQ( @Context UriInfo ui, @QueryParam("fq_access_token") String fq_access_token,
@QueryParam("ttl") long ttl, @QueryParam("callback") @DefaultValue("") String callback )
throws Exception {
if (logger.isTraceEnabled()) {
logger.trace("AuthResource.authFQ");
}
try {
if ( StringUtils.isEmpty( fq_access_token ) ) {
return missingTokenFail( callback );
}
SignInAsProvider foursquareProvider = signInProviderFactory.foursquare( services.getApplication() );
User user = foursquareProvider.createOrAuthenticate( fq_access_token );
if ( user == null ) {
return findAndCreateFail( callback );
}
String token = management.getAccessTokenForAppUser( services.getApplicationId(), user.getUuid(), ttl );
AccessInfo access_info =
new AccessInfo().withExpiresIn( tokens.getMaxTokenAgeInSeconds( token ) ).withAccessToken( token )
.withProperty( "user", user );
return Response.status( SC_OK ).type( jsonMediaType( callback ) )
.entity( wrapWithCallback( access_info, callback ) ).build();
}
catch ( Exception e ) {
return generalAuthError( callback, e );
}
}
}