diff --git a/.classpath b/.classpath index 91f2707..ffa5a81 100644 --- a/.classpath +++ b/.classpath @@ -6,15 +6,11 @@ - - - - - + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 443e085..8db228c 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -5,4 +5,5 @@ org.eclipse.jdt.core.compiler.compliance=1.7 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.release=disabled org.eclipse.jdt.core.compiler.source=1.7 diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component index 0543109..b6f63af 100644 --- a/.settings/org.eclipse.wst.common.component +++ b/.settings/org.eclipse.wst.common.component @@ -1,5 +1,5 @@ - + diff --git a/pom.xml b/pom.xml index 3372b09..c2e1c38 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -12,11 +13,11 @@ org.gcube.portal oauth war - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT gcube-oauth - 1.7 + 1.8 2.22.1 ${project.basedir}/distro ${project.build.directory}/${project.build.finalName} @@ -44,6 +45,11 @@ + + net.spy + spymemcached + 2.12.3 + org.glassfish.jersey.containers diff --git a/src/main/java/org/gcube/portal/oauth/OauthService.java b/src/main/java/org/gcube/portal/oauth/OauthService.java index b183760..b6d8e44 100644 --- a/src/main/java/org/gcube/portal/oauth/OauthService.java +++ b/src/main/java/org/gcube/portal/oauth/OauthService.java @@ -2,9 +2,8 @@ package org.gcube.portal.oauth; import static org.gcube.common.authorization.client.Constants.authorizationService; +import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import javax.inject.Singleton; import javax.servlet.http.HttpServletRequest; @@ -26,13 +25,13 @@ import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.utils.Caller; import org.gcube.common.scope.api.ScopeProvider; import org.gcube.portal.oauth.cache.CacheBean; -import org.gcube.portal.oauth.cache.CacheCleaner; import org.gcube.portal.oauth.input.PushCodeBean; import org.gcube.portal.oauth.output.AccessTokenBeanResponse; import org.gcube.portal.oauth.output.AccessTokenErrorResponse; -import org.gcube.smartgears.Constants; import org.slf4j.LoggerFactory; +import net.spy.memcached.MemcachedClient; + @Path("/v2") @Singleton @@ -40,21 +39,18 @@ public class OauthService { public static final String OAUTH_TOKEN_GET_METHOD_NAME_REQUEST = "access-token"; private static final String GRANT_TYPE_VALUE = "authorization_code"; - private static final String AUTHORIZATION_HEADER = "Authorization"; + private static final int CACHE_SECONDS_EXPIRATION = 10; private static final org.slf4j.Logger logger = LoggerFactory.getLogger(OauthService.class); /** * This map contains couples */ - private Map entries; + private MemcachedClient entries; + - /** - * Cleaner thread - */ - CacheCleaner cleaner; /** * Since this is a singleton sub-service, there will be just one call to this constructor and one running thread @@ -62,15 +58,12 @@ public class OauthService { */ public OauthService() { logger.info("Singleton gcube-oauth service built."); - entries = new ConcurrentHashMap(); - cleaner = new CacheCleaner(entries); - cleaner.start(); + entries = DistributedCacheClient.getInstance().getMemcachedClient(); } @Override protected void finalize(){ - if(cleaner != null) - cleaner.interrupt(); + entries.shutdown(); } /** @@ -106,12 +99,14 @@ public class OauthService { @Produces(MediaType.APPLICATION_JSON) @Path("push-authentication-code") /** + * CALLED FROM THE PORTAL PORTLET to pass among the other the temp code which expires in 10 seconds + * * The portal will push a qualified token together a code * @return Response with status 201 if the code has been saved correctly */ public Response pushAuthCode(PushCodeBean bean) { - logger.info("Request to push "); + logger.info("Request to push aothCode from the portal "); Caller caller = AuthorizationProvider.instance.get(); String token = SecurityTokenProvider.instance.get(); @@ -141,7 +136,7 @@ public class OauthService { entity("{\"error\"=\"'redirect_uri' cannot be null or missing\"").build(); logger.info("Saving entry defined by " + bean + " in cache, token is " + token.substring(0, 10) + "***************"); - entries.put(code, new CacheBean(token, ScopeProvider.instance.get(), redirectUri, clientId, System.currentTimeMillis())); + entries.set(code, CACHE_SECONDS_EXPIRATION, new CacheBean(token, ScopeProvider.instance.get(), redirectUri, clientId)); return Response.status(status).build(); } @@ -194,8 +189,8 @@ public class OauthService { return Response.status(status).entity(new AccessTokenErrorResponse(errorMessage, null)).build(); }else{ logger.info("The request is ok"); - String tokenToReturn = entries.get(code).getToken(); - String scope = entries.get(code).getScope(); + String tokenToReturn = ((CacheBean) entries.get(code)).getToken(); + String scope = ((CacheBean)entries.get(code)).getScope(); status = Status.OK; return Response.status(status).entity(new AccessTokenBeanResponse(tokenToReturn, scope)).build(); } @@ -212,8 +207,15 @@ public class OauthService { String credentials = new String(DatatypeConverter.parseBase64Binary(base64Credentials)); // credentials = username:password String[] splitCreds = credentials.split(":"); - String clientId = URLDecoder.decode(splitCreds[0]); - String clientSecret = URLDecoder.decode(splitCreds[1]); + String clientId = null; + String clientSecret = null; + try { + clientId = URLDecoder.decode(splitCreds[0], java.nio.charset.StandardCharsets.UTF_8.toString()); + clientSecret = URLDecoder.decode(splitCreds[1], java.nio.charset.StandardCharsets.UTF_8.toString()); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } return new CredentialsBean(clientId, clientSecret); } @@ -236,9 +238,9 @@ public class OauthService { return "invalid_request"; if(!checkIsapplicationTokenType(authorizationService().get(credentials.getClientSecret()).getClientInfo().getType())) // it is not an app token or it is not a token return "invalid_client"; - if(!entries.containsKey(code) || CacheBean.isExpired(entries.get(code))) + if(entries.get(code) == null) return "invalid_grant"; - CacheBean entry = entries.get(code); + CacheBean entry = (CacheBean) entries.get(code); if(!entry.getRedirectUri().equals(redirectUri) || !entry.getClientId().equals(credentials.getClientId())) return "invalid_grant"; if(!grantType.equals(GRANT_TYPE_VALUE)) diff --git a/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java b/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java index a904be9..899ad78 100644 --- a/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java +++ b/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java @@ -1,19 +1,25 @@ package org.gcube.portal.oauth.cache; +import java.io.Serializable; + /** * A cache bean object for oauth support * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @author Massimiliano Assante, National Research Council of Italy (CNR) - ISTI */ -public class CacheBean { +@SuppressWarnings("serial") +public class CacheBean implements Serializable { private String token; private String scope; private String redirectUri; private String clientId; - private Long insertTime; - private static final int TOKEN_TTL = 1000 * 10; + public CacheBean() { + super(); + } + /** * @param token * @param scope @@ -21,14 +27,12 @@ public class CacheBean { * @param clientId * @param insertTime */ - public CacheBean(String token, String scope, String redirectUri, - String clientId, Long insertTime) { + public CacheBean(String token, String scope, String redirectUri, String clientId) { super(); this.token = token; this.scope = scope; this.redirectUri = redirectUri; this.clientId = clientId; - this.insertTime = insertTime; } public String getScope() { @@ -47,14 +51,6 @@ public class CacheBean { this.token = token; } - public Long getInsertTime() { - return insertTime; - } - - public void setInsertTime(Long insertTime) { - this.insertTime = insertTime; - } - public String getRedirectUri() { return redirectUri; } @@ -73,19 +69,16 @@ public class CacheBean { @Override public String toString() { - return "CacheBean [token=" + token + ", scope=" + scope - + ", redirectUri=" + redirectUri + ", clientId=" + clientId - + ", insertTime=" + insertTime + "]"; - } - - /** - * True if the code expired, false otherwise - * @return - */ - public static boolean isExpired(CacheBean bean){ - - return System.currentTimeMillis() > TOKEN_TTL + bean.insertTime; - - } - + StringBuilder builder = new StringBuilder(); + builder.append("CacheBean [token="); + builder.append(token); + builder.append(", scope="); + builder.append(scope); + builder.append(", redirectUri="); + builder.append(redirectUri); + builder.append(", clientId="); + builder.append(clientId); + builder.append("]"); + return builder.toString(); + } }