diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..91f2707
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..dd99283
--- /dev/null
+++ b/.project
@@ -0,0 +1,42 @@
+
+
+ oauth
+
+
+
+
+
+ org.eclipse.wst.jsdt.core.javascriptValidator
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.wst.common.project.facet.core.builder
+
+
+
+
+ org.eclipse.wst.validation.validationbuilder
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.wst.common.modulecore.ModuleCoreNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.m2e.core.maven2Nature
+ org.eclipse.wst.common.project.facet.core.nature
+ org.eclipse.wst.jsdt.core.jsNature
+
+
diff --git a/.settings/.jsdtscope b/.settings/.jsdtscope
new file mode 100644
index 0000000..b72a6a4
--- /dev/null
+++ b/.settings/.jsdtscope
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..839d647
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..443e085
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,8 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+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.source=1.7
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/.settings/org.eclipse.wst.common.component b/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..09dd0d8
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..cc81385
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.common.project.facet.core.xml b/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..fffd28a
--- /dev/null
+++ b/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.container b/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.jsdt.ui.superType.name b/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000..04cad8c
--- /dev/null
+++ b/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..50447cf
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,178 @@
+
+
+ 4.0.0
+
+ maven-parent
+ org.gcube.tools
+ 1.0.0
+
+
+
+ org.gcube.portal
+ oauth
+ war
+ 1.0.0-SNAPSHOT
+ oauth gCube App
+
+
+ 1.7
+ 2.22.1
+ ${project.basedir}/distro
+ ${project.build.directory}/${project.build.finalName}
+ distro
+ UTF-8
+ UTF-8
+
+
+
+ scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/portal/${project.artifactId}
+ scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/portal/${project.artifactId}
+ http://svn.d4science.research-infrastructures.eu/gcube/trunk/portal/${project.artifactId}
+
+
+
+
+
+ org.gcube.distribution
+ maven-smartgears-bom
+ LATEST
+ pom
+ import
+
+
+
+
+
+
+
+ org.gcube.core
+ common-smartgears
+ provided
+
+
+ org.gcube.core
+ common-smartgears-app
+ compile
+
+
+ javax.servlet
+ servlet-api
+ 3.0-alpha-1
+ compile
+
+
+ org.glassfish.jersey.containers
+
+ jersey-container-servlet-core
+ ${version.jersey}
+
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+ ${version.jersey}
+
+
+ org.glassfish.jersey.media
+ jersey-media-json-processing
+ ${version.jersey}
+
+
+ org.glassfish.jersey.media
+ jersey-media-multipart
+ ${version.jersey}
+
+
+ org.glassfish.jersey.media
+ jersey-media-sse
+ ${version.jersey}
+
+
+ org.glassfish.jersey.ext
+ jersey-bean-validation
+ ${version.jersey}
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+
+ ${name}
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ 2.1.1
+
+
+ compile
+
+ exploded
+
+
+
+
+ ${webappDirectory}
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+
+ 1.7
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 2.2
+
+
+ ${distroDirectory}/descriptor.xml
+
+
+
+
+ servicearchive
+ install
+
+ single
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 2.5
+
+
+ copy-profile
+ install
+
+ copy-resources
+
+
+ target
+
+
+ ${distroDirectory}
+ true
+
+ profile.xml
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/gcube/portal/oauth/OauthService.java b/src/main/java/org/gcube/portal/oauth/OauthService.java
new file mode 100644
index 0000000..8ca4c36
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/OauthService.java
@@ -0,0 +1,174 @@
+package org.gcube.portal.oauth;
+
+import static org.gcube.common.authorization.client.Constants.authorizationService;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.inject.Singleton;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.gcube.common.authorization.library.ClientType;
+import org.gcube.common.authorization.library.provider.AuthorizationProvider;
+import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
+import org.gcube.common.authorization.library.utils.Caller;
+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.slf4j.LoggerFactory;
+
+
+@Path("v2/")
+@Singleton
+public class OauthService {
+
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(OauthService.class);
+
+ /**
+ * This map contains couples
+ */
+ private Map entries = new ConcurrentHashMap();
+
+ /**
+ * Since this is a singleton sub-service, there will be just one call to this constructor and one running thread
+ * to clean up expired codes.
+ */
+ public OauthService() {
+ CacheCleaner cleaner = new CacheCleaner(entries);
+ cleaner.start();
+ }
+
+ /**
+ * Used to check that the token type is of type user
+ * @param clientType
+ * @param token
+ * @return
+ */
+ private boolean checkIsQualifierTokenType(ClientType clientType){
+ return clientType.equals(ClientType.USER);
+ }
+
+ /**
+ * Used to check that the token type is of type application
+ * @param clientType
+ * @param token
+ * @return
+ */
+ private boolean checkIsapplicationTokenType(ClientType clientType){
+ return clientType.equals(ClientType.EXTERNALSERVICE);
+ }
+
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("push-authentication-code")
+ /**
+ * 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 ");
+
+ Caller caller = AuthorizationProvider.instance.get();
+ String token = SecurityTokenProvider.instance.get();
+ Status status = Status.CREATED;
+
+ if(!checkIsQualifierTokenType(caller.getClient().getType())){
+ status = Status.FORBIDDEN;
+ logger.warn("Trying to access users method via a token different than USER is not allowed");
+ return Response.status(status).entity("{\"error\"=\"Trying to access push-authentication-code method via a token different than USER is not allowed\"").build();
+ }else{
+
+ logger.info("Saving entry defined by " + bean + " in cache, token is " + token.substring(0, 10));
+ entries.put(bean.getCode(), new CacheBean(token, bean.getRedirectUri(), bean.getClientId(), System.currentTimeMillis()));
+ return Response.status(status).build();
+ }
+
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("access-token")
+ /**
+ * The method should accept input values or in a json object or as FormParam. The request is validated here and not from SmartGears.
+ * @param requestInJson
+ * @param clientId
+ * @param clientSecret
+ * @param redirectUri
+ * @param code
+ * @param grantType
+ * @return
+ */
+ public Response tokenRequest(
+ @FormParam("client_id") String clientId,
+ @FormParam("client_secret") String clientSecret, // i.e., application token
+ @FormParam("redirect_uri") String redirectUri,
+ @FormParam("code") String code,
+ @FormParam("grant_type") String grantType // it must always be equal to "authorization_code"
+ ){
+
+ Status status = Status.BAD_REQUEST;
+ logger.info("Request to exchange code for token");
+ logger.info("Params are + client_id = " + clientId + ", client_secret = " + clientSecret.substring(0, 10) + ", redirect_uri = " +redirectUri + ", code = " + code.substring(0, 10));
+
+ try{
+ // check if something is missing
+ String errorMessage = checkRequest(clientId, clientSecret, redirectUri, code, grantType);
+ if(errorMessage != null){
+ logger.error("The request fails because of " + errorMessage);
+ return Response.status(status).entity(new AccessTokenErrorResponse(errorMessage, null, null)).build();
+ }else{
+ logger.info("The request is ok");
+ String tokenToReturn = entries.get(code).getToken();
+ status = Status.OK;
+ return Response.status(status).entity(new AccessTokenBeanResponse(tokenToReturn, authorizationService().get(tokenToReturn).getContext())).build();
+ }
+ }catch(Exception e){
+ logger.error("Failed to perform this operation", e);
+ status = Status.BAD_REQUEST;
+ return Response.status(status).entity(new AccessTokenErrorResponse("invalid_request", null, null)).build();
+ }
+ }
+
+ /**
+ * Check request parameters
+ * @param clientId
+ * @param clientSecret
+ * @param redirectUri
+ * @param code
+ * @param grantType
+ * @return see https://tools.ietf.org/html/rfc6749#section-5.2
+ */
+ private String checkRequest(String clientId, String clientSecret,
+ String redirectUri, String code, String grantType) {
+
+ try{
+ if(clientId == null || clientSecret == null || redirectUri == null || code == null || grantType == null)
+ return "invalid_request";
+ if(clientId.isEmpty() || clientSecret.isEmpty() || redirectUri.isEmpty() || code.isEmpty() || grantType.isEmpty())
+ return "invalid_request";
+ if(!checkIsapplicationTokenType(authorizationService().get(clientSecret).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)))
+ return "invalid_grant";
+ if(!grantType.equals("authorization_code"))
+ return "unsupported_grant_type";
+ return null;
+ }catch(Exception e){
+ logger.error("Failed to check the correctness of the request", e);
+ return "invalid_request";
+ }
+ }
+}
diff --git a/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java b/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java
new file mode 100644
index 0000000..5201ef9
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/cache/CacheBean.java
@@ -0,0 +1,79 @@
+package org.gcube.portal.oauth.cache;
+
+
+/**
+ * A cache bean object for oauth support
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class CacheBean {
+
+ private String token;
+ private String redirectUri;
+ private String clientId;
+ private Long insertTime;
+ private static final int TOKEN_TTL = 1000 * 10;
+
+ /**
+ * @param token
+ * @param redirectUri
+ * @param clientId
+ * @param insertTime
+ */
+ public CacheBean(String token, String redirectUri, String clientId,
+ Long insertTime) {
+ super();
+ this.token = token;
+ this.redirectUri = redirectUri;
+ this.clientId = clientId;
+ this.insertTime = insertTime;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public Long getInsertTime() {
+ return insertTime;
+ }
+
+ public void setInsertTime(Long insertTime) {
+ this.insertTime = insertTime;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ @Override
+ public String toString() {
+ return "CacheBean [token=" + token + ", 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;
+
+ }
+
+}
diff --git a/src/main/java/org/gcube/portal/oauth/cache/CacheCleaner.java b/src/main/java/org/gcube/portal/oauth/cache/CacheCleaner.java
new file mode 100644
index 0000000..c8f2690
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/cache/CacheCleaner.java
@@ -0,0 +1,60 @@
+package org.gcube.portal.oauth.cache;
+
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This thread cleans a cache by removing expired entries.
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class CacheCleaner extends Thread {
+
+ private Map cacheReference;
+ private static final int CHECK_AFTER_MS = 1000 * 60 * 10;
+
+ private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CacheCleaner.class);
+
+ /**
+ * Build a cleaner thread.
+ * @param cache
+ */
+ public CacheCleaner(Map cache) {
+ this.cacheReference = cache;
+ }
+
+ @Override
+ public void run() {
+
+ while (!isInterrupted()) {
+
+ try {
+
+ sleep(CHECK_AFTER_MS);
+ logger.info("Going to clean up cache and old codes [" + new Date() + "]");
+
+ Iterator> iterator = cacheReference.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry entry = (Map.Entry) iterator
+ .next();
+ if(CacheBean.isExpired(entry.getValue())){
+ logger.debug("Removing entry " + entry.getValue());
+ iterator.remove();
+ }
+ }
+
+ logger.info("Going to sleep [" + new Date() + "]");
+
+ } catch (InterruptedException e) {
+ logger.warn("Exception was " + e.getMessage());
+ continue;
+ }
+
+ }
+ }
+
+}
diff --git a/src/main/java/org/gcube/portal/oauth/input/PushCodeBean.java b/src/main/java/org/gcube/portal/oauth/input/PushCodeBean.java
new file mode 100644
index 0000000..15ed14f
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/input/PushCodeBean.java
@@ -0,0 +1,67 @@
+package org.gcube.portal.oauth.input;
+
+import javax.validation.constraints.NotNull;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * The code to be pushed into the cache of codes (plus some other informations)
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class PushCodeBean {
+
+ @JsonProperty("code")
+ @NotNull(message="code cannot be null")
+ private String code;
+
+ @JsonProperty("redirect_uri")
+ @NotNull(message="redirect_uri cannot be null")
+ private String redirectUri;
+
+ @JsonProperty("client_id")
+ @NotNull(message="client_id cannot be null")
+ private String clientId;
+
+ /**
+ * @param code
+ * @param redirectUri
+ * @param clientId
+ */
+ public PushCodeBean(String code, String redirectUri, String clientId) {
+ super();
+ this.code = code;
+ this.redirectUri = redirectUri;
+ this.clientId = clientId;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ @Override
+ public String toString() {
+ return "PushCodeBean [code=" + code + ", redirectUri=" + redirectUri
+ + ", clientId=" + clientId + "]";
+ }
+
+}
diff --git a/src/main/java/org/gcube/portal/oauth/output/AccessTokenBeanResponse.java b/src/main/java/org/gcube/portal/oauth/output/AccessTokenBeanResponse.java
new file mode 100644
index 0000000..e22ed12
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/output/AccessTokenBeanResponse.java
@@ -0,0 +1,62 @@
+package org.gcube.portal.oauth.output;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Response to a request token.
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class AccessTokenBeanResponse {
+
+ @JsonProperty("access_token")
+ private String accessToken;
+
+ @JsonProperty("expires_in")
+ private static final Long expiresIn = Long.MAX_VALUE; // the number of seconds remaining (max long value)
+
+ @JsonProperty("scope")
+ private String scope;
+
+ @JsonProperty("token_type")
+ private static final String tokenType = "Bearer";
+
+ /**
+ * @param accessToken
+ * @param scope
+ */
+ public AccessTokenBeanResponse(String accessToken, String scope) {
+ super();
+ this.accessToken = accessToken;
+ this.scope = scope;
+ }
+
+ public static Long getExpiresin() {
+ return expiresIn;
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public static String getTokentype() {
+ return tokenType;
+ }
+
+ @Override
+ public String toString() {
+ return "AccessTokenBeanResponse [accessToken=" + accessToken
+ + ", scope=" + scope + "]";
+ }
+}
diff --git a/src/main/java/org/gcube/portal/oauth/output/AccessTokenErrorResponse.java b/src/main/java/org/gcube/portal/oauth/output/AccessTokenErrorResponse.java
new file mode 100644
index 0000000..afd60da
--- /dev/null
+++ b/src/main/java/org/gcube/portal/oauth/output/AccessTokenErrorResponse.java
@@ -0,0 +1,66 @@
+package org.gcube.portal.oauth.output;
+
+import javax.validation.constraints.NotNull;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * Bean used on failed request
+ * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
+ */
+public class AccessTokenErrorResponse {
+
+ @NotNull
+ @JsonProperty("error")
+ private String error;
+
+ @JsonProperty("error_description")
+ private String errorDescription;
+
+ @JsonProperty("error_uri")
+ private String errorUri;
+
+ /**
+ * @param error
+ * @param errorDescription
+ * @param errorUri
+ */
+ public AccessTokenErrorResponse(String error, String errorDescription,
+ String errorUri) {
+ super();
+ this.error = error;
+ this.errorDescription = errorDescription;
+ this.errorUri = errorUri;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+ public String getErrorDescription() {
+ return errorDescription;
+ }
+
+ public void setErrorDescription(String errorDescription) {
+ this.errorDescription = errorDescription;
+ }
+
+ public String getErrorUri() {
+ return errorUri;
+ }
+
+ public void setErrorUri(String errorUri) {
+ this.errorUri = errorUri;
+ }
+
+ @Override
+ public String toString() {
+ return "AccessTokenErrorResponse [error=" + error
+ + ", errorDescription=" + errorDescription + ", errorUri="
+ + errorUri + "]";
+ }
+}
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..9f88c1f
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,7 @@
+
+
+
+ Archetype Created Web Application
+
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
new file mode 100644
index 0000000..767f206
--- /dev/null
+++ b/src/main/webapp/index.jsp
@@ -0,0 +1,5 @@
+
+
+ The gCube OAUTH web service is up and running!
+
+