diff --git a/src/main/java/org/gatein/api/Portal.java b/src/main/java/org/gatein/api/Portal.java index 1b35657..22ae379 100644 --- a/src/main/java/org/gatein/api/Portal.java +++ b/src/main/java/org/gatein/api/Portal.java @@ -23,6 +23,7 @@ package org.gatein.api; import org.gatein.api.navigation.Navigation; +import org.gatein.api.oauth.OAuthProvider; import org.gatein.api.page.Page; import org.gatein.api.page.PageId; import org.gatein.api.page.PageQuery; @@ -178,4 +179,13 @@ public interface Portal { * @throws ApiException if something prevented this operation to succeed */ boolean hasPermission(User user, Permission permission); + + /** + * Return {@link org.gatein.api.oauth.OAuthProvider} for given key. Key could be {@link OAuthProvider#FACEBOOK}, + * {@link OAuthProvider#GOOGLE}, {@link OAuthProvider#TWITTER} or other OAuth provider registered in Portal via OAuth SPI + * + * @param oauthProviderKey Key of OAuth provider + * @return OAuth provider or null if OAuth provider with given key was not found + */ + OAuthProvider getOAuthProvider(String oauthProviderKey); } diff --git a/src/main/java/org/gatein/api/oauth/AccessToken.java b/src/main/java/org/gatein/api/oauth/AccessToken.java new file mode 100644 index 0000000..b2f282d --- /dev/null +++ b/src/main/java/org/gatein/api/oauth/AccessToken.java @@ -0,0 +1,64 @@ +/* + * JBoss, a division of Red Hat + * Copyright 2013, Red Hat Middleware, LLC, and individual + * contributors as indicated by the @authors tag. See the + * copyright.txt in the distribution for a full listing of + * individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.gatein.api.oauth; + +import java.io.Serializable; + +/** + * Access token object, which encapsulates all important informations about OAuth1 or OAuth2 access token + * + * @author Marek Posolda + */ +public interface AccessToken extends Serializable { + + /** + * Return list of all available scopes in single String. Scopes are divided by delimiter character (usually space). + * + *

In OAuth specification, each scope represents some kind of permission. So note that this access token could be used only to + * call operations, for which scope is available.

+ * + *

For example: scope "email" could be used in Facebook to retrive information about user's email address. So if you have this + * scope, you can use this access token object to retrieve email address of this user from Facebook.

+ * + * @return list of all available scopes in single String + */ + String getAvailableScopes(); + + /** + * Return true if given scope is available in list of OAuth scopes of this access token + * + * @param scope to test + * @return true if given scope is available + * @see @getAvailableScopes + */ + boolean isScopeAvailable(String scope); + + /** + * Return string representation of this access token. Note that it may not be enough in some cases, so this operation is + * useful only for some OAuth providers + * + * @return access token + */ + String getAccessToken(); +} diff --git a/src/main/java/org/gatein/api/oauth/OAuthProvider.java b/src/main/java/org/gatein/api/oauth/OAuthProvider.java new file mode 100644 index 0000000..f15cd16 --- /dev/null +++ b/src/main/java/org/gatein/api/oauth/OAuthProvider.java @@ -0,0 +1,147 @@ +/* + * JBoss, a division of Red Hat + * Copyright 2013, Red Hat Middleware, LLC, and individual + * contributors as indicated by the @authors tag. See the + * copyright.txt in the distribution for a full listing of + * individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.gatein.api.oauth; + +import java.io.IOException; + +import org.gatein.api.oauth.exception.OAuthApiException; +import org.gatein.api.oauth.exception.OAuthApiExceptionCode; + +/** + * Object, which represents single OAuth provider (Social network). It's used to interact with Portal to load/save needed + * informations or inform Portal that we want to start some OAuth actions. + * + * @author Marek Posolda + */ +public interface OAuthProvider { + + /** + * Key under which Facebook OAuth provider is registered + */ + static final String FACEBOOK = "FACEBOOK"; + + /** + * Key under which Google+ OAuth provider is registered + */ + static final String GOOGLE = "GOOGLE"; + + /** + * Key under which Twitter OAuth provider is registered + */ + static final String TWITTER = "TWITTER"; + + /** + * Return key of this OAuth provider. For example {@link #FACEBOOK} + * + * @return key of this OAuth provider + */ + String getKey(); + + /** + * Return friendly name of this OAuth provider. For example "Facebook". It might be useful for messages, which will be shown + * to end user + * + * @return friendly name of this OAuth provider + */ + String getFriendlyName(); + + /** + * Return access token for given user from portal identity storage (DB or LDAP). Return null if access token wasn't found + * + * @param username name of portal user + * @return access token of given user + * @throws OAuthApiException if error occured. Error code would be {@link OAuthApiExceptionCode#PERSISTENCE_ERROR} if error + * occured in communication between Portal and Identity storage (DB or LDAP) + */ + AccessToken loadAccessToken(String username) throws OAuthApiException; + + /** + * Save access token for given user to portal identity storage (DB or LDAP) + * + * @param username name of portal user + * @param accessToken access token to save + * @throws OAuthApiException if error occured. Error code would be {@link OAuthApiExceptionCode#PERSISTENCE_ERROR} if error + * occured in communication between Portal and Identity storage (DB or LDAP) + */ + void saveAccessToken(String username, AccessToken accessToken) throws OAuthApiException; + + /** + * Remove access token of given user from portal identity storage (DB or LDAP) + * + * @param username name of portal user + * @throws OAuthApiException if error occured. Error code would be {@link OAuthApiExceptionCode#PERSISTENCE_ERROR} if error + * occured in communication between Portal and Identity storage (DB or LDAP) + */ + void removeAccessToken(String username) throws OAuthApiException; + + /** + * Start OAuth or OAuth2 workflow, which means redirection to OAuth provider (Social network) login screen and authorization + * screen and obtaining of access token for current portal user. After calling this method, current Servlet request is finished because it's redirected + * to OAuth provider + * + *

After whole OAuth workflow is successfully finished, you can obtain access token of current user via + * {@link #loadAccessToken(String)}

+ * + * @param neededCustomScope required OAuth scope. This parameter can be null and in this case, OAuth workflow will be started + * just with scopes from Portal configuration + * @throws OAuthApiException if this operation is not supported or some other OAuth error occured + * @throws IOException if some I/O error occured (For example when calling redirecting current Servlet response) + */ + void startOAuthWorkflow(String neededCustomScope) throws OAuthApiException, IOException; + + /** + * Check if given access token is valid and possibly update some info (like scopes or access token itself if it was refreshed) + * In case that access token has been refreshed (updated) you may call {@link #saveAccessToken(String, AccessToken)} to update + * it in DB (it's not done by Portal itself during call of this method) + * + * @param accessToken access token to validate + * @return Validated access token with all refreshed info (In some cases it could be equal to passed access token) + * @throws OAuthApiException if error occured during validation. Error code could be {@link OAuthApiExceptionCode#ACCESS_TOKEN_ERROR} + * if passed access token is invalid or revoked, or {@link OAuthApiExceptionCode#IO_ERROR} if network error happened during + * communication with OAuth provider + */ + AccessToken validateTokenAndUpdateScopes(AccessToken accessToken) throws OAuthApiException; + + /** + * Revoke current access token on OAuth provider side, so access token won't be valid anymore and portal application + * can't be seen in list of available applications of OAuth provider (For example: + * https://www.facebook.com/settings?tab=applications in case of Facebook) + * + * @param accessToken access token to revoke + * @throws OAuthApiException with code {@link OAuthApiExceptionCode#TOKEN_REVOCATION_FAILED} if revocation failed + * (For example network error or access token has been already revoked before) + */ + void revokeToken(AccessToken accessToken) throws OAuthApiException; + + /** + * Return "accessor" object, which can be used to call some operations on Social network + * + * @param accessToken access token used to initialize object + * @param socialApiObjectType Type of requested social API object + * @return Instance of requested social API object + * @throws OAuthApiException with code {@link OAuthApiExceptionCode#SOCIAL_API_OBJECT_NOT_FOUND} if object of requested type + * is not supported by this OAuth provider + */ + T getAuthorizedSocialApiObject(AccessToken accessToken, Class socialApiObjectType) throws OAuthApiException; +} diff --git a/src/main/java/org/gatein/api/oauth/exception/OAuthApiException.java b/src/main/java/org/gatein/api/oauth/exception/OAuthApiException.java new file mode 100644 index 0000000..a2b1cff --- /dev/null +++ b/src/main/java/org/gatein/api/oauth/exception/OAuthApiException.java @@ -0,0 +1,63 @@ +/* + * JBoss, a division of Red Hat + * Copyright 2013, Red Hat Middleware, LLC, and individual + * contributors as indicated by the @authors tag. See the + * copyright.txt in the distribution for a full listing of + * individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.gatein.api.oauth.exception; + +import org.gatein.api.ApiException; + +/** + * ApiException when calling some OAuth operation + * + * @author Marek Posolda + */ +public class OAuthApiException extends ApiException { + + private final OAuthApiExceptionCode exceptionCode; + + public OAuthApiException(final OAuthApiExceptionCode exceptionCode, final String message) { + super(message); + this.exceptionCode = exceptionCode; + } + + public OAuthApiException(final OAuthApiExceptionCode exceptionCode, final String message, final Throwable t) { + super(message, t); + this.exceptionCode = exceptionCode; + } + + /** + * Return exception code, which specifies which OAuth error actually happened + * + * @return exception code + */ + public OAuthApiExceptionCode getExceptionCode() { + return exceptionCode; + } + + /** + * {@inheritDoc} + */ + @Override + public String getMessage() { + return exceptionCode + ": " + super.getMessage(); + } +} diff --git a/src/main/java/org/gatein/api/oauth/exception/OAuthApiExceptionCode.java b/src/main/java/org/gatein/api/oauth/exception/OAuthApiExceptionCode.java new file mode 100644 index 0000000..3781a77 --- /dev/null +++ b/src/main/java/org/gatein/api/oauth/exception/OAuthApiExceptionCode.java @@ -0,0 +1,72 @@ +/* + * JBoss, a division of Red Hat + * Copyright 2013, Red Hat Middleware, LLC, and individual + * contributors as indicated by the @authors tag. See the + * copyright.txt in the distribution for a full listing of + * individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.gatein.api.oauth.exception; + +/** + * Exception code of OAuth error + * + * @author Marek Posolda + * @see OAuthApiException + */ +public enum OAuthApiExceptionCode { + + /** + * This error could happen during saving of user into GateIn identity database. + * It happens when there is an attempt to save user with facebookUsername (or googleUsername), but there is already an existing + * user with same facebookUsername. + * + * For example: We want to save user 'john' with facebookUsername 'john.doyle' but we already have user 'johny2' with same facebookUsername 'john.doyle' + */ + DUPLICATE_OAUTH_PROVIDER_USERNAME, + + /** + * Error when we have invalid or revoked access token + */ + ACCESS_TOKEN_ERROR, + + /** + * Generic IO error (for example network error) + */ + IO_ERROR, + + /** + * Error when revoking of accessToken of any provider failed + */ + TOKEN_REVOCATION_FAILED, + + /** + * Error during DB operation (For example get/set/remove access token from DB) + */ + PERSISTENCE_ERROR, + + /** + * Thrown when object of specified type wasn't found or couldn't be obtained and initialized + */ + SOCIAL_API_OBJECT_NOT_FOUND, + + /** + * Some other error + */ + OTHER_ERROR, +}