Implemented OAuth2 authorization error response using redirect URI.
Change-Id: Id79f3eec0beacaca792fb3130e3e41f5d9bbc7ad
diff --git a/full/Changes b/full/Changes
index ccb3096..4c99586 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,9 +1,10 @@
version 0.60.4
-12/06/2018
+18/06/2018
- implemented OAuth2 authorization code request with OpenID Authentication (margaretha)
- enabled OAuth2 authorization without OpenID authentication using Nimbus library (margaretha)
- implemented response handler for OpenID authentication errors in authorization requests (margaretha)
- added tests regarding OpenID authentication in authorization requests (margaretha)
+ - implemented OAuth2 authorization error response via redirect URI instead of JSON (margaretha)
version 0.60.3
06/06/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
index c0353be..77f8e17 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
@@ -1,5 +1,8 @@
package de.ids_mannheim.korap.oauth2.oltu.service;
+import java.net.URI;
+import java.net.URISyntaxException;
+
import javax.servlet.http.HttpServletRequest;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
@@ -13,6 +16,8 @@
import com.sun.jersey.api.client.ClientResponse.Status;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
import de.ids_mannheim.korap.oauth2.service.OAuth2AuthorizationService;
@@ -35,29 +40,60 @@
* @param request
* @param authzRequest
* @param username
- * @return
+ * @return redirect URI containing authorization code if
+ * successful.
+ *
* @throws KustvaktException
* @throws OAuthSystemException
*/
public String requestAuthorizationCode (HttpServletRequest request,
OAuthAuthzRequest authzRequest, String username)
- throws KustvaktException, OAuthSystemException {
+ throws OAuthSystemException, KustvaktException {
String code = oauthIssuer.authorizationCode();
checkResponseType(authzRequest.getResponseType());
String clientId = authzRequest.getClientId();
OAuth2Client client = clientService.authenticateClientId(clientId);
-
+
String redirectUri = authzRequest.getRedirectURI();
String verifiedRedirectUri = verifyRedirectUri(client, redirectUri);
- String scope = createAuthorization(username, authzRequest.getClientId(),
- redirectUri, authzRequest.getScopes(), code);
- OAuthResponse oAuthResponse = OAuthASResponse
- .authorizationResponse(request, Status.FOUND.getStatusCode())
- .setCode(code).setScope(scope)
- .location(verifiedRedirectUri).buildQueryMessage();
+ URI redirectURI;
+ try {
+ redirectURI = new URI(verifiedRedirectUri);
+ }
+ catch (URISyntaxException e) {
+ throw new KustvaktException(StatusCodes.INVALID_REDIRECT_URI,
+ "Invalid redirect URI", OAuth2Error.INVALID_REQUEST);
+ }
+
+ String scope;
+ try {
+ scope = createAuthorization(username, authzRequest.getClientId(),
+ redirectUri, authzRequest.getScopes(), code);
+ }
+ catch (KustvaktException e) {
+ e.setRedirectUri(redirectURI);
+ throw e;
+ }
+
+ OAuthResponse oAuthResponse;
+ try {
+ oAuthResponse = OAuthASResponse
+ .authorizationResponse(request,
+ Status.FOUND.getStatusCode())
+ .setCode(code).setScope(scope).location(verifiedRedirectUri)
+ .buildQueryMessage();
+ }
+ catch (OAuthSystemException e) {
+ // Should not happen
+ KustvaktException ke =
+ new KustvaktException(StatusCodes.OAUTH2_SYSTEM_ERROR,
+ e.getMessage(), OAuth2Error.SERVER_ERROR);
+ ke.setRedirectUri(redirectURI);
+ throw ke;
+ }
return oAuthResponse.getLocationUri();
}
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java b/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
index f6a223c..d244e90 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/OAuth2ResponseHandler.java
@@ -4,6 +4,7 @@
import java.net.URISyntaxException;
import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
@@ -13,6 +14,7 @@
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
+import org.apache.oltu.oauth2.common.message.OAuthResponse.OAuthErrorResponseBuilder;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -105,10 +107,37 @@
int statusCode) throws OAuthSystemException {
OAuthProblemException oAuthProblemException = OAuthProblemException
.error(e.getEntity()).description(e.getMessage());
- return OAuthResponse.errorResponse(statusCode)
- .error(oAuthProblemException).buildJSONMessage();
+
+ OAuthErrorResponseBuilder responseBuilder = OAuthResponse
+ .errorResponse(statusCode).error(oAuthProblemException);
+ URI redirectUri = e.getRedirectUri();
+ if (redirectUri != null) {
+ responseBuilder.location(redirectUri.toString());
+ return responseBuilder.buildQueryMessage();
+ }
+
+ return responseBuilder.buildJSONMessage();
}
+ /**
+ * RFC 6749 regarding authorization error response:
+ *
+ * If the request fails due to a missing, invalid, or mismatching
+ * redirection URI, or if the client identifier is missing or
+ * invalid, the authorization server SHOULD inform the resource
+ * owner of the error and MUST NOT automatically redirect the
+ * user-agent to the invalid redirection URI.
+ *
+ * If the resource owner denies the access request or if the
+ * request fails for reasons other than a missing or invalid
+ * redirection URI, the authorization server informs the client by
+ * adding the following parameters to the query component of the
+ * redirection URI using the "application/x-www-form-urlencoded"
+ * format.
+ *
+ * @param oAuthResponse
+ * @return
+ */
public Response createResponse (OAuthResponse oAuthResponse) {
ResponseBuilder builder =
Response.status(oAuthResponse.getResponseStatus());
@@ -121,6 +150,17 @@
builder.header(HttpHeaders.WWW_AUTHENTICATE,
"Basic realm=\"Kustvakt\"");
}
+ String uri = oAuthResponse.getLocationUri();
+ if (uri != null && !uri.isEmpty()) {
+ try {
+ builder.location(new URI(uri));
+ builder.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
+ }
+ catch (URISyntaxException e) {
+ e.printStackTrace();
+ }
+ }
+
return builder.build();
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java b/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
index 4c50d75..21cecdb 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/OpenIdResponseHandler.java
@@ -4,6 +4,7 @@
import java.util.HashMap;
import java.util.Map;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
@@ -104,7 +105,8 @@
state, responseMode).toURI();
}
- ResponseBuilder builder = Response.temporaryRedirect(uri);
+ ResponseBuilder builder = Response.temporaryRedirect(uri)
+ .type(MediaType.APPLICATION_FORM_URLENCODED);
return builder.build();
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
index 4b2e19e..6614f11 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2Controller.java
@@ -79,9 +79,9 @@
TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
String username = tokenContext.getUsername();
+ HttpServletRequest requestWithForm =
+ new FormRequestWrapper(request, form);
try {
- HttpServletRequest requestWithForm =
- new FormRequestWrapper(request, form);
OAuth2AuthorizationRequest authzRequest =
new OAuth2AuthorizationRequest(requestWithForm);
String uri = authorizationService.requestAuthorizationCode(
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
index d3605de..82affd6 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuth2WithOpenIdController.java
@@ -5,7 +5,6 @@
import javax.servlet.http.HttpServletRequest;
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;
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
index bd66b74..f7aa89a 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
@@ -140,11 +140,11 @@
ClientResponse response = requestAuthorizationConfidentialClient(form);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- String entity = response.getEntity(String.class);
- JsonNode node = JsonUtils.readTree(entity);
- assertEquals(OAuth2Error.INVALID_SCOPE, node.at("/error").asText());
- assertEquals("read_address is an invalid scope",
- node.at("/error_description").asText());
+ URI location = response.getLocation();
+ MultiValueMap<String, String> params =
+ UriComponentsBuilder.fromUri(location).build().getQueryParams();
+ assertEquals(OAuth2Error.INVALID_SCOPE, params.getFirst("error"));
+ assertEquals("read_address+is+an+invalid+scope", params.getFirst("error_description"));
}
private ClientResponse requestToken (MultivaluedMap<String, String> form)
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
index fc35235..d4a337d 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -5,6 +5,7 @@
import java.net.URI;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.http.entity.ContentType;
@@ -167,7 +168,7 @@
ClientResponse response = sendAuthorizationRequest(form);
URI location = response.getLocation();
- // System.out.println(location);
+ assertEquals(MediaType.APPLICATION_FORM_URLENCODED, response.getType().toString());
MultiValueMap<String, String> params =
UriComponentsBuilder.fromUri(location).build().getQueryParams();