diff --git a/social/pom.xml b/social/pom.xml index bb982ebf33..435b8e399a 100755 --- a/social/pom.xml +++ b/social/pom.xml @@ -31,30 +31,26 @@ org.jboss.spec.javax.ejb jboss-ejb-api_3.2_spec - provided 1.0.0.Alpha2 + provided com.google.api-client google-api-client - provided com.google.http-client google-http-client-jackson - provided com.google.apis google-api-services-oauth2 - provided org.twitter4j twitter4j-core - provided diff --git a/social/src/main/java/org/keycloak/social/IdentityProvider.java b/social/src/main/java/org/keycloak/social/IdentityProvider.java index 202e82da78..c48d4fa2f9 100644 --- a/social/src/main/java/org/keycloak/social/IdentityProvider.java +++ b/social/src/main/java/org/keycloak/social/IdentityProvider.java @@ -37,7 +37,7 @@ public interface IdentityProvider { String getId(); @XmlTransient - URI getAuthUrl(IdentityProviderCallback callback); + URI getAuthUrl(IdentityProviderCallback callback) throws IdentityProviderException; String getName(); @@ -45,6 +45,6 @@ public interface IdentityProvider { boolean isCallbackHandler(IdentityProviderCallback callback); @XmlTransient - User processCallback(IdentityProviderCallback callback); + User processCallback(IdentityProviderCallback callback) throws IdentityProviderException; } diff --git a/social/src/main/java/org/keycloak/social/IdentityProviderErrors.java b/social/src/main/java/org/keycloak/social/IdentityProviderErrors.java new file mode 100644 index 0000000000..ed5ddb0dbc --- /dev/null +++ b/social/src/main/java/org/keycloak/social/IdentityProviderErrors.java @@ -0,0 +1,6 @@ +package org.keycloak.social; + +public class IdentityProviderErrors { + public static final String INVALID_PROVIDER = "invalid_provider"; + public static final String PROVIDER_ERROR = "provider_error"; +} diff --git a/social/src/main/java/org/keycloak/social/IdentityProviderException.java b/social/src/main/java/org/keycloak/social/IdentityProviderException.java new file mode 100644 index 0000000000..6d011e29cb --- /dev/null +++ b/social/src/main/java/org/keycloak/social/IdentityProviderException.java @@ -0,0 +1,11 @@ +package org.keycloak.social; + +public class IdentityProviderException extends Exception { + + private static final long serialVersionUID = 1L; + + public IdentityProviderException(Throwable cause) { + super(cause); + } + +} diff --git a/social/src/main/java/org/keycloak/social/google/GoogleProvider.java b/social/src/main/java/org/keycloak/social/google/GoogleProvider.java index cb180c9bc7..9530278f68 100644 --- a/social/src/main/java/org/keycloak/social/google/GoogleProvider.java +++ b/social/src/main/java/org/keycloak/social/google/GoogleProvider.java @@ -24,9 +24,9 @@ package org.keycloak.social.google; import java.net.URI; import java.util.UUID; -import org.jboss.resteasy.logging.Logger; import org.keycloak.social.IdentityProvider; import org.keycloak.social.IdentityProviderCallback; +import org.keycloak.social.IdentityProviderException; import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.User; @@ -46,8 +46,6 @@ public class GoogleProvider implements IdentityProvider { private static final JacksonFactory JSON_FACTORY = new JacksonFactory(); - private static final Logger log = Logger.getLogger(GoogleProvider.class); - private static final NetHttpTransport TRANSPORT = new NetHttpTransport(); @Override @@ -81,7 +79,7 @@ public class GoogleProvider implements IdentityProvider { } @Override - public User processCallback(IdentityProviderCallback callback) { + public User processCallback(IdentityProviderCallback callback) throws IdentityProviderException { String code = callback.getQueryParam("code"); try { @@ -109,8 +107,7 @@ public class GoogleProvider implements IdentityProvider { return user; } catch (Exception e) { - log.error("Failed to process callback", e); - return null; + throw new IdentityProviderException(e); } } diff --git a/social/src/main/java/org/keycloak/social/resources/SocialApplication.java b/social/src/main/java/org/keycloak/social/resources/SocialApplication.java new file mode 100644 index 0000000000..a332b5a4aa --- /dev/null +++ b/social/src/main/java/org/keycloak/social/resources/SocialApplication.java @@ -0,0 +1,9 @@ +package org.keycloak.social.resources; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("social/api") +public class SocialApplication extends Application { + +} diff --git a/social/src/main/java/org/keycloak/social/resources/SocialResource.java b/social/src/main/java/org/keycloak/social/resources/SocialResource.java index ec8c5dec45..4d5c174e1d 100644 --- a/social/src/main/java/org/keycloak/social/resources/SocialResource.java +++ b/social/src/main/java/org/keycloak/social/resources/SocialResource.java @@ -41,8 +41,11 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; +import org.jboss.resteasy.logging.Logger; import org.keycloak.social.IdentityProvider; import org.keycloak.social.IdentityProviderCallback; +import org.keycloak.social.IdentityProviderErrors; +import org.keycloak.social.IdentityProviderException; import org.keycloak.social.IdentityProviderState; import org.keycloak.social.util.UriBuilder; import org.picketlink.idm.model.Attribute; @@ -51,9 +54,11 @@ import org.picketlink.idm.model.User; /** * @author Stian Thorgersen */ -@Path("social") +@Path("") public class SocialResource { + private static final Logger log = Logger.getLogger(SocialResource.class); + // TODO This is just temporary - need to either save state variables somewhere they can be flushed after a timeout, or // alternatively they could be saved in http session, but that is probably not a good idea private static final Map states = new HashMap(); @@ -89,9 +94,12 @@ public class SocialResource { callback.setProviderState(getProviderState(provider)); if (provider.isCallbackHandler(callback)) { - User user = provider.processCallback(callback); - if (user == null) { - break; + User user = null; + try { + user = provider.processCallback(callback); + } catch (IdentityProviderException e) { + log.warn("Failed to process callback", e); + redirectToLogin(application, IdentityProviderErrors.PROVIDER_ERROR); } String providerUsername = user.getLoginName(); @@ -135,6 +143,7 @@ public class SocialResource { @GET @Path("providers") + @Produces(MediaType.APPLICATION_JSON) public List getProviders() { List providers = new LinkedList(); Iterator itr = ServiceRegistry.lookupProviders(IdentityProvider.class); @@ -170,13 +179,12 @@ public class SocialResource { } private Response redirectToLogin(String application, String error) { - URI uri = new UriBuilder(headers, uriInfo, "login?application=" + application + "&error=login_failed").build(); + URI uri = new UriBuilder(headers, uriInfo, "sdk/api/" + application + "/login").setQueryParam("error", error).build(); return Response.seeOther(uri).build(); } @GET @Path("{application}/auth/{provider}") - @Produces(MediaType.TEXT_HTML) public Response redirectToProviderAuth(@PathParam("application") String application, @PathParam("provider") String providerId) { Iterator itr = ServiceRegistry.lookupProviders(IdentityProvider.class); @@ -186,7 +194,8 @@ public class SocialResource { } if (provider == null) { - return redirectToLogin(application, "invalid_provider"); + log.warn("Failed to redirect to provider auth: " + providerId + " not found"); + return redirectToLogin(application, IdentityProviderErrors.INVALID_PROVIDER); } IdentityProviderCallback callback = new IdentityProviderCallback(); @@ -195,12 +204,13 @@ public class SocialResource { callback.setUriInfo(uriInfo); callback.setProviderKey(null); // TODO Get provider key callback.setProviderSecret(null); // TODO Get provider secret + callback.setProviderState(getProviderState(provider)); - URI authUrl = provider.getAuthUrl(callback); - if (authUrl != null) { - return Response.seeOther(authUrl).build(); - } else { - return redirectToLogin(application, "invalid_provider"); + try { + return Response.seeOther(provider.getAuthUrl(callback)).build(); + } catch (Throwable t) { + log.warn("Failed to redirect to provider auth", t); + return redirectToLogin(application, IdentityProviderErrors.PROVIDER_ERROR); } } diff --git a/social/src/main/java/org/keycloak/social/twitter/TwitterProvider.java b/social/src/main/java/org/keycloak/social/twitter/TwitterProvider.java index 3a28e14b4f..58ea524bf4 100644 --- a/social/src/main/java/org/keycloak/social/twitter/TwitterProvider.java +++ b/social/src/main/java/org/keycloak/social/twitter/TwitterProvider.java @@ -23,9 +23,9 @@ package org.keycloak.social.twitter; import java.net.URI; -import org.jboss.resteasy.logging.Logger; import org.keycloak.social.IdentityProvider; import org.keycloak.social.IdentityProviderCallback; +import org.keycloak.social.IdentityProviderException; import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.User; @@ -38,15 +38,13 @@ import twitter4j.auth.RequestToken; */ public class TwitterProvider implements IdentityProvider { - private static final Logger log = Logger.getLogger(TwitterProvider.class); - @Override public String getId() { return "twitter"; } @Override - public URI getAuthUrl(IdentityProviderCallback callback) { + public URI getAuthUrl(IdentityProviderCallback callback) throws IdentityProviderException { try { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(callback.getProviderKey(), callback.getProviderSecret()); @@ -55,8 +53,7 @@ public class TwitterProvider implements IdentityProvider { callback.putState(requestToken.getToken(), requestToken); return callback.createUri(requestToken.getAuthenticationURL()).build(); } catch (Exception e) { - log.error("Failed to retrieve login url", e); - return null; + throw new IdentityProviderException(e); } } @@ -71,7 +68,7 @@ public class TwitterProvider implements IdentityProvider { } @Override - public User processCallback(IdentityProviderCallback callback) { + public User processCallback(IdentityProviderCallback callback) throws IdentityProviderException { try { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(callback.getProviderKey(), callback.getProviderSecret()); @@ -86,8 +83,7 @@ public class TwitterProvider implements IdentityProvider { user.setFirstName(twitterUser.getName()); return user; } catch (Exception e) { - log.error("Failed to process callback", e); - return null; + throw new IdentityProviderException(e); } } diff --git a/social/src/main/resources/META-INF/services/org.eventjuggler.services.idb.provider.IdentityProvider b/social/src/main/resources/META-INF/services/org.keycloak.social.IdentityProvider similarity index 100% rename from social/src/main/resources/META-INF/services/org.eventjuggler.services.idb.provider.IdentityProvider rename to social/src/main/resources/META-INF/services/org.keycloak.social.IdentityProvider