Implemented degrading super clients, improved and added OAuth2 tests.
Change-Id: I1359149050dd3609dfdb4d72d1bc2ca11b95cded
diff --git a/full/Changes b/full/Changes
index 81f9b88..60bf81a 100644
--- a/full/Changes
+++ b/full/Changes
@@ -19,6 +19,9 @@
- Marked native clients implementation to deprecated in favour of super clients (margaretha)
- Enabled using Bearer tokens as user authentication tokens (Authorization header value) for many
controllers including OAuth2 controllers (margaretha)
+16/08/2018
+ - Implemented degrading super clients (margaretha)
+ - Improved and added OAuth2 tests (margaretha)
# version 0.60.5
diff --git a/full/src/main/java/de/ids_mannheim/korap/constant/TokenType.java b/full/src/main/java/de/ids_mannheim/korap/constant/TokenType.java
index 6d5a00b..418be0b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/constant/TokenType.java
+++ b/full/src/main/java/de/ids_mannheim/korap/constant/TokenType.java
@@ -1,5 +1,7 @@
package de.ids_mannheim.korap.constant;
+import org.apache.commons.lang.StringUtils;
+
public enum TokenType {
BASIC, API, SESSION,
// openid token, e.g. within oauth2 response (json body)
@@ -10,6 +12,6 @@
CLIENT;
public String displayName () {
- return name().toLowerCase();
+ return StringUtils.capitalize(name().toLowerCase());
}
}
\ No newline at end of file
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
index 16ff581..1aba796 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
@@ -341,7 +341,6 @@
String tokenType = revokeTokenRequest.getTokenType();
clientService.authenticateClient(clientId, clientSecret);
- tokenDao.removeCacheEntry(token);
if (tokenType != null && tokenType.equals("refresh_token")) {
if (!revokeRefreshToken(token)) {
revokeAccessToken(token);
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index cdd6a66..6e8803a 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -183,23 +183,7 @@
|| client.getRegisteredBy().equals(username)) {
clientDao.deregisterClient(client);
-
- // revoke all related authorization tokens
- List<Authorization> authList =
- authorizationDao.retrieveAuthorizationsByClientId(clientId);
- for (Authorization authorization : authList) {
- authorization.setRevoked(true);
- authorizationDao.updateAuthorization(authorization);
- }
-
- // revoke all related access tokens
- List<AccessToken> tokens =
- tokenDao.retrieveAccessTokenByClientId(clientId);
- for (AccessToken token : tokens) {
- token.setRevoked(true);
- token.setRefreshTokenRevoked(true);
- tokenDao.updateAccessToken(token);
- }
+ revokeAllAuthorizationsByClientId(clientId);
}
else {
throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
@@ -207,6 +191,27 @@
}
}
+ private void revokeAllAuthorizationsByClientId (String clientId)
+ throws KustvaktException {
+
+ // revoke all related authorization codes
+ List<Authorization> authList =
+ authorizationDao.retrieveAuthorizationsByClientId(clientId);
+ for (Authorization authorization : authList) {
+ authorization.setRevoked(true);
+ authorizationDao.updateAuthorization(authorization);
+ }
+
+ // revoke all related access tokens
+ List<AccessToken> tokens =
+ tokenDao.retrieveAccessTokenByClientId(clientId);
+ for (AccessToken token : tokens) {
+ token.setRevoked(true);
+ token.setRefreshTokenRevoked(true);
+ tokenDao.updateAccessToken(token);
+ }
+ }
+
public OAuth2ClientDto resetSecret (String clientId, String clientSecret,
String username) throws KustvaktException {
@@ -258,8 +263,8 @@
OAuth2Error.INVALID_REQUEST);
}
}
- else if (client.getSecret() == null || client.getSecret().isEmpty()){
- if (client.getType().equals(OAuth2ClientType.CONFIDENTIAL)){
+ else if (client.getSecret() == null || client.getSecret().isEmpty()) {
+ if (client.getType().equals(OAuth2ClientType.CONFIDENTIAL)) {
throw new KustvaktException(
StatusCodes.CLIENT_AUTHENTICATION_FAILED,
"Client secret was not registered",
@@ -291,11 +296,16 @@
if (adminDao.isAdmin(username)) {
OAuth2Client client = clientDao.retrieveClientById(clientId);
- if (isSuper && !client.getType()
- .equals(OAuth2ClientType.CONFIDENTIAL)) {
- throw new KustvaktException(StatusCodes.NOT_ALLOWED,
- "Only confidential clients are allowed to be super clients.");
+ if (isSuper) {
+ if (!client.getType().equals(OAuth2ClientType.CONFIDENTIAL)) {
+ throw new KustvaktException(StatusCodes.NOT_ALLOWED,
+ "Only confidential clients are allowed to be super clients.");
+ }
}
+ else {
+ revokeAllAuthorizationsByClientId(clientId);
+ }
+
client.setSuper(isSuper);
clientDao.updateClient(client);
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
index 91a129d..08889cd 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
@@ -172,10 +172,17 @@
* setting a specific client to be a super client.
* Only confidential clients are allowed to be super clients.
*
+ * When upgrading clients to super clients, existing access tokens
+ * and authorization codes retain their scopes.
+ *
+ * When degrading super clients, all existing tokens and
+ * authorization codes are invalidated.
+ *
* @param securityContext
- * @param clientId
- * @param super true indicating super client, false otherwise
- * @return Response status OK, if successful
+ * @param clientId OAuth2 client id
+ * @param super
+ * true indicating super client, false otherwise
+ * @return Response status OK, if successful
*/
@POST
@Path("privilege")
@@ -189,8 +196,7 @@
try {
scopeService.verifyScope(context, OAuth2Scope.ADMIN);
clientService.updatePrivilege(context.getUsername(), clientId,
- true);
-// Boolean.valueOf(isSuper));
+ Boolean.valueOf(isSuper));
return Response.ok().build();
}
catch (KustvaktException e) {
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
index 78d91aa..93cf3c2 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
@@ -5,17 +5,13 @@
import static org.junit.Assert.assertTrue;
import java.io.IOException;
-import java.net.URI;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response.Status;
import org.apache.http.entity.ContentType;
import org.apache.oltu.oauth2.common.message.types.GrantType;
-import org.apache.oltu.oauth2.common.message.types.TokenType;
import org.junit.Test;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.net.HttpHeaders;
@@ -24,102 +20,29 @@
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.constant.TokenType;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
import de.ids_mannheim.korap.utils.JsonUtils;
-public class OAuth2AccessTokenTest extends SpringJerseyTest {
+public class OAuth2AccessTokenTest extends OAuth2TestBase {
- // normal client
- private String clientId = "9aHsGW6QflV13ixNpez";
- private String superClientId = "fCBbQkAyYzI4NzUxMg";
- private String clientSecret = "secret";
+ private String userAuthHeader;
+ private String clientAuthHeader;
- private String requestAuthorizationCode (String scope, String authHeader)
- throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("response_type", "code");
- form.add("client_id", clientId);
- form.add("client_secret", clientSecret);
- if (scope != null) {
- form.add("scope", scope);
- }
-
- ClientResponse response = resource().path("oauth2").path("authorize")
- .header(Attributes.AUTHORIZATION, authHeader)
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
- response.getStatus());
- URI redirectUri = response.getLocation();
- MultiValueMap<String, String> params = UriComponentsBuilder
- .fromUri(redirectUri).build().getQueryParams();
- return params.getFirst("code");
- }
-
- // client credentials as form params
- private JsonNode requestTokenWithAuthorizationCodeGrant ()
- throws KustvaktException {
- String authHeader = HttpAuthorizationHandler
+ public OAuth2AccessTokenTest () throws KustvaktException {
+ userAuthHeader = HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue("dory", "password");
- String code = requestAuthorizationCode(null, authHeader);
-
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "authorization_code");
- form.add("client_id", clientId);
- form.add("client_secret", clientSecret);
- form.add("code", code);
-
- ClientResponse response = resource().path("oauth2").path("token")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- String entity = response.getEntity(String.class);
- assertEquals(Status.OK.getStatusCode(), response.getStatus());
- JsonNode node = JsonUtils.readTree(entity);
- return node;
- }
-
- // client credentials in authorization header
- private JsonNode requestTokenWithAuthorizationHeader (String code)
- throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "authorization_code");
- form.add("client_id", clientId);
- form.add("code", code);
-
- ClientResponse response = resource().path("oauth2").path("token")
- .header(Attributes.AUTHORIZATION,
- HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue(clientId,
- clientSecret))
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- String entity = response.getEntity(String.class);
- return JsonUtils.readTree(entity);
+ clientAuthHeader =
+ HttpAuthorizationHandler.createBasicAuthorizationHeaderValue(
+ confidentialClientId, clientSecret);
}
@Test
public void testScopeWithSuperClient () throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("client_id", superClientId);
- form.add("client_secret", clientSecret);
- form.add("username", "dory");
- form.add("password", "password");
-
- ClientResponse response = resource().path("oauth2").path("token")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
+ ClientResponse response =
+ requestTokenWithPassword(superClientId, clientSecret);
JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
assertEquals("all", node.at("/scope").asText());
@@ -136,18 +59,19 @@
}
@Test
- public void testCustomAuthorizationScope () throws KustvaktException {
- String authHeader = HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue("dory", "password");
- String code = requestAuthorizationCode(OAuth2Scope.VC_INFO.toString(),
- authHeader);
- JsonNode node = requestTokenWithAuthorizationHeader(code);
+ public void testCustomScope () throws KustvaktException {
+ String code = requestAuthorizationCode(confidentialClientId,
+ clientSecret, OAuth2Scope.VC_INFO.toString(), userAuthHeader);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, code);
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
String token = node.at("/access_token").asText();
assertTrue(node.at("/scope").asText()
.contains(OAuth2Scope.VC_INFO.toString()));
- ClientResponse response = resource().path("vc").path("list")
+ // test list vc using the token
+ response = resource().path("vc").path("list")
.header(Attributes.AUTHORIZATION, "Bearer " + token)
.get(ClientResponse.class);
@@ -158,14 +82,20 @@
@Test
public void testDefaultScope () throws KustvaktException, IOException {
- String accessToken = requestTokenWithAuthorizationCodeGrant()
- .at("/access_token").asText();
- testListVCScopeNotAuthorized(accessToken);
- testListVCAccessBearerNotAuthorize(accessToken);
+ String code = requestAuthorizationCode(confidentialClientId, clientSecret,
+ null, userAuthHeader);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, code);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ String accessToken = node.at("/access_token").asText();
+ testScopeNotAuthorized(accessToken);
+ testScopeNotAuthorize2(accessToken);
testSearchWithOAuth2Token(accessToken);
}
- private void testListVCScopeNotAuthorized (String accessToken)
+ private void testScopeNotAuthorized (String accessToken)
throws KustvaktException {
ClientResponse response = resource().path("vc").path("list")
.header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
@@ -181,7 +111,7 @@
node.at("/errors/0/1").asText());
}
- private void testListVCAccessBearerNotAuthorize (String accessToken)
+ private void testScopeNotAuthorize2 (String accessToken)
throws KustvaktException {
ClientResponse response =
resource().path("vc").path("access").path("list")
@@ -200,18 +130,11 @@
private void testSearchWithOAuth2Token (String accessToken)
throws KustvaktException, IOException {
- ClientResponse response = resource().path("search")
- .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
- .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .get(ClientResponse.class);
-
- String ent = response.getEntity(String.class);
-
+ ClientResponse response = searchWithAccessToken(accessToken);
+ String entity = response.getEntity(String.class);
assertEquals(ClientResponse.Status.OK.getStatusCode(),
response.getStatus());
-
- JsonNode node = JsonUtils.readTree(ent);
+ JsonNode node = JsonUtils.readTree(entity);
assertNotNull(node);
assertEquals(25, node.at("/matches").size());
}
@@ -219,11 +142,8 @@
@Test
public void testSearchWithUnknownToken ()
throws KustvaktException, IOException {
- ClientResponse response = resource().path("search")
- .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
- .header(Attributes.AUTHORIZATION,
- "Bearer ljsa8tKNRSczJhk20öhq92zG8z350")
- .get(ClientResponse.class);
+ ClientResponse response =
+ searchWithAccessToken("ljsa8tKNRSczJhk20öhq92zG8z350");
assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
response.getStatus());
@@ -239,11 +159,15 @@
@Test
public void testRevokeAccessTokenConfidentialClient ()
throws KustvaktException {
- String accessToken = requestTokenWithAuthorizationCodeGrant()
- .at("/access_token").asText();
+ String code = requestAuthorizationCode(confidentialClientId,
+ clientSecret, null, userAuthHeader);
+ JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
+ confidentialClientId, code, clientAuthHeader);
+
+ String accessToken = node.at("/access_token").asText();
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("token", accessToken);
- form.add("client_id", clientId);
+ form.add("client_id", confidentialClientId);
form.add("client_secret", "secret");
ClientResponse response = resource().path("oauth2").path("revoke")
@@ -253,17 +177,12 @@
assertEquals(Status.OK.getStatusCode(), response.getStatus());
- testSearchWithRevokedToken(accessToken);
+ testSearchWithRevokedAccessToken(accessToken);
}
- private void testSearchWithRevokedToken (String accessToken)
+ private void testSearchWithRevokedAccessToken (String accessToken)
throws KustvaktException {
- ClientResponse response = resource().path("search")
- .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
- .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .get(ClientResponse.class);
-
+ ClientResponse response = searchWithAccessToken(accessToken);
String entity = response.getEntity(String.class);
assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
response.getStatus());
@@ -273,19 +192,22 @@
node.at("/errors/0/0").asInt());
assertEquals("Access token has been revoked",
node.at("/errors/0/1").asText());
-
}
@Test
- public void testRevocationAfterRequestRefreshToken ()
+ public void testRevokedAccessTokenAfterRequestRefreshToken ()
throws KustvaktException {
- JsonNode node = requestTokenWithAuthorizationCodeGrant();
+ String code = requestAuthorizationCode(confidentialClientId,
+ clientSecret, null, userAuthHeader);
+ JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
+ confidentialClientId, code, clientAuthHeader);
+
String accessToken = node.at("/access_token").asText();
String refreshToken = node.at("/refresh_token").asText();
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
- form.add("client_id", clientId);
+ form.add("client_id", confidentialClientId);
form.add("client_secret", "secret");
form.add("refresh_token", refreshToken);
@@ -302,17 +224,21 @@
assertNotNull(node.at("/access_token").asText());
assertEquals(refreshToken, node.at("/refresh_token").asText());
- testSearchWithRevokedToken(accessToken);
+ testSearchWithRevokedAccessToken(accessToken);
}
@Test
- public void testRequestAuthorizationWithBearerTokenUnauthorized () throws KustvaktException {
- String userAuthToken = requestTokenWithAuthorizationCodeGrant()
- .at("/access_token").asText();
+ public void testRequestAuthorizationWithBearerTokenUnauthorized ()
+ throws KustvaktException {
+ String code = requestAuthorizationCode(confidentialClientId,
+ clientSecret, null, userAuthHeader);
+ JsonNode node = requestTokenWithAuthorizationCodeAndHeader(
+ confidentialClientId, code, clientAuthHeader);
+ String userAuthToken = node.at("/access_token").asText();
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "code");
- form.add("client_id", clientId);
+ form.add("client_id", confidentialClientId);
form.add("client_secret", clientSecret);
ClientResponse response = resource().path("oauth2").path("authorize")
@@ -323,8 +249,8 @@
.entity(form).post(ClientResponse.class);
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
-
- JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+
+ node = JsonUtils.readTree(response.getEntity(String.class));
assertEquals(StatusCodes.AUTHORIZATION_FAILED,
node.at("/errors/0/0").asInt());
assertEquals("Scope authorize is not authorized",
@@ -334,31 +260,20 @@
@Test
public void testRequestAuthorizationWithBearerToken ()
throws KustvaktException {
- String userAuthToken = requestTokenWithPasswordGrant();
- String code = requestAuthorizationCode(null, "Bearer " + userAuthToken);
+ ClientResponse response =
+ requestTokenWithPassword(superClientId, clientSecret);
+ String entity = response.getEntity(String.class);
+
+ JsonNode node = JsonUtils.readTree(entity);
+ String userAuthToken = node.at("/access_token").asText();
+ assertNotNull(userAuthToken);
+ assertEquals(TokenType.BEARER.displayName(),
+ node.at("/token_type").asText());
+ assertNotNull(node.at("/expires_in").asText());
+
+ String code = requestAuthorizationCode(superClientId,
+ clientSecret, null, "Bearer " + userAuthToken);
assertNotNull(code);
}
- private String requestTokenWithPasswordGrant () throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("client_id", superClientId);
- form.add("client_secret", clientSecret);
- form.add("username", "dory");
- form.add("password", "password");
-
- ClientResponse response = resource().path("oauth2").path("token")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
- String entity = response.getEntity(String.class);
-
- JsonNode node = JsonUtils.readTree(entity);
- String token = node.at("/access_token").asText();
- assertNotNull(token);
- assertEquals(TokenType.BEARER.toString(),
- node.at("/token_type").asText());
- assertNotNull(node.at("/expires_in").asText());
- return token;
- }
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
index 9c3d536..aa32cb3 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
@@ -4,7 +4,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import java.net.URI;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
@@ -13,8 +12,6 @@
import org.apache.http.entity.ContentType;
import org.junit.Test;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.util.UriComponentsBuilder;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.net.HttpHeaders;
@@ -27,7 +24,6 @@
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.SpringJerseyTest;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
@@ -39,9 +35,15 @@
* @author margaretha
*
*/
-public class OAuth2ClientControllerTest extends SpringJerseyTest {
+public class OAuth2ClientControllerTest extends OAuth2TestBase {
private String username = "OAuth2ClientControllerTest";
+ private String userAuthHeader;
+
+ public OAuth2ClientControllerTest () throws KustvaktException {
+ userAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue("dory", "password");
+ }
private void checkWWWAuthenticateHeader (ClientResponse response) {
Set<Entry<String, List<String>>> headers =
@@ -73,6 +75,21 @@
.entity(json).post(ClientResponse.class);
}
+ private JsonNode retrieveClientInfo (String clientId, String username)
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+ ClientResponse response = resource().path("oauth2").path("client")
+ .path("info").path(clientId)
+ .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(username, "pass"))
+ .get(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ String entity = response.getEntity(String.class);
+ return JsonUtils.readTree(entity);
+ }
+
@Test
public void testRegisterConfidentialClient () throws KustvaktException {
ClientResponse response = registerConfidentialClient();
@@ -127,7 +144,7 @@
assertTrue(node.at("/client_secret").isMissingNode());
testResetPublicClientSecret(clientId);
- testAccessTokenAfterDeregistration(clientId);
+ testAccessTokenAfterDeregistration(clientId, null);
}
@Test
@@ -158,20 +175,26 @@
testDeregisterPublicClient(clientId);
}
- private void testAccessTokenAfterDeregistration (String clientId)
- throws KustvaktException {
- String code = requestAuthorizationCode(clientId, "");
- ClientResponse response = requestAccessToken(code, clientId, "");
+ private void testAccessTokenAfterDeregistration (String clientId,
+ String clientSecret) throws KustvaktException {
+ String userAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue("dory", "password");
+
+ String code =
+ requestAuthorizationCode(clientId, "", null, userAuthHeader);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(clientId,
+ clientSecret, code);
JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
String accessToken = node.at("/access_token").asText();
response = searchWithAccessToken(accessToken);
assertEquals(Status.OK.getStatusCode(), response.getStatus());
- code = requestAuthorizationCode(clientId, "");
+ code = requestAuthorizationCode(clientId, "", null, userAuthHeader);
testDeregisterPublicClient(clientId);
- response = requestAccessToken(code, clientId, "");
+ response = requestTokenWithAuthorizationCodeAndForm(clientId,
+ clientSecret, code);
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
node = JsonUtils.readTree(response.getEntity(String.class));
assertEquals(OAuth2Error.INVALID_CLIENT.toString(),
@@ -184,59 +207,6 @@
node.at("/errors/0/0").asInt());
assertEquals("Access token has been revoked",
node.at("/errors/0/1").asText());
-
- }
-
- private String requestAuthorizationCode (String clientId,
- String clientSecret) throws UniformInterfaceException,
- ClientHandlerException, KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("response_type", "code");
- form.add("client_id", clientId);
- form.add("client_secret", clientSecret);
-
- ClientResponse response = resource().path("oauth2").path("authorize")
- .header(Attributes.AUTHORIZATION,
- HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue("dory",
- "password"))
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
- response.getStatus());
- URI redirectUri = response.getLocation();
- MultiValueMap<String, String> params = UriComponentsBuilder
- .fromUri(redirectUri).build().getQueryParams();
- return params.getFirst("code");
- }
-
- private ClientResponse requestAccessToken (String code, String clientId,
- String clientSecret) throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "authorization_code");
- form.add("client_id", clientId);
- form.add("client_secret", clientSecret);
- form.add("code", code);
-
- ClientResponse response = resource().path("oauth2").path("token")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- return response;
- }
-
- private ClientResponse searchWithAccessToken (String accessToken) {
- ClientResponse response = resource().path("search")
- .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
- .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .get(ClientResponse.class);
-
- return response;
}
private void testDeregisterPublicClientMissingUserAuthentication (
@@ -395,52 +365,74 @@
@Test
public void testUpdateClientPrivilege () throws KustvaktException {
+ // register a client
ClientResponse response = registerConfidentialClient();
JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
String clientId = node.at("/client_id").asText();
+ String clientSecret = node.at("/client_secret").asText();
+ // request an access token
+ String clientAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(clientId, clientSecret);
+ String code = requestAuthorizationCode(clientId, clientSecret, null,
+ userAuthHeader);
+ node = requestTokenWithAuthorizationCodeAndHeader(clientId, code,
+ clientAuthHeader);
+ String accessToken = node.at("/access_token").asText();
+
+ testAccessTokenAfterUpgradingClient(clientId, accessToken);
+ testAccessTokenAfterDegradingSuperClient(clientId, accessToken);
+ }
+
+ // old access tokens retain their scopes
+ private void testAccessTokenAfterUpgradingClient (String clientId,
+ String accessToken) throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("client_id", clientId);
form.add("super", "true");
updateClientPrivilege(form);
- node = retrieveClientInfo(clientId, "admin");
+ JsonNode node = retrieveClientInfo(clientId, "admin");
assertTrue(node.at("/isSuper").asBoolean());
- form.remove("super");
- form.add("super", "false");
- updateClientPrivilege(form);
- node = retrieveClientInfo(clientId, username);
- assertTrue(node.at("/isSuper").isMissingNode());
-
- }
-
- private void updateClientPrivilege (MultivaluedMap<String, String> form)
- throws UniformInterfaceException, ClientHandlerException,
- KustvaktException {
- ClientResponse response = resource().path("oauth2").path("client")
- .path("privilege")
- .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue("admin", "pass"))
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
-
- assertEquals(Status.OK.getStatusCode(), response.getStatus());
- }
-
- private JsonNode retrieveClientInfo (String clientId, String username)
- throws UniformInterfaceException, ClientHandlerException,
- KustvaktException {
- ClientResponse response = resource().path("oauth2").path("client")
- .path("info").path(clientId)
- .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue(username, "pass"))
+ // list vc
+ ClientResponse response = resource().path("vc").path("list")
+ .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
.get(ClientResponse.class);
- assertEquals(Status.OK.getStatusCode(), response.getStatus());
-
+ assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+ response.getStatus());
String entity = response.getEntity(String.class);
- return JsonUtils.readTree(entity);
+ node = JsonUtils.readTree(entity);
+ assertEquals(StatusCodes.AUTHORIZATION_FAILED,
+ node.at("/errors/0/0").asInt());
+ assertEquals("Scope vc_info is not authorized",
+ node.at("/errors/0/1").asText());
+
+ // search
+ response = searchWithAccessToken(accessToken);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ }
+
+ private void testAccessTokenAfterDegradingSuperClient (String clientId,
+ String accessToken) throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("client_id", clientId);
+ form.add("super", "false");
+
+ updateClientPrivilege(form);
+ JsonNode node = retrieveClientInfo(clientId, username);
+ assertTrue(node.at("/isSuper").isMissingNode());
+
+ ClientResponse response = searchWithAccessToken(accessToken);
+ assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+ response.getStatus());
+
+ String entity = response.getEntity(String.class);
+ node = JsonUtils.readTree(entity);
+ assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
+ node.at("/errors/0/0").asInt());
+ assertEquals("Access token has been revoked",
+ node.at("/errors/0/1").asText());
}
}
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 5d452e8..d5c7140 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
@@ -23,8 +23,6 @@
import com.sun.jersey.core.util.MultivaluedMapImpl;
import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.SpringJerseyTest;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
import de.ids_mannheim.korap.utils.JsonUtils;
@@ -33,29 +31,24 @@
* @author margaretha
*
*/
-public class OAuth2ControllerTest extends SpringJerseyTest {
+public class OAuth2ControllerTest extends OAuth2TestBase {
- private ClientResponse requestAuthorization (
- MultivaluedMap<String, String> form) throws KustvaktException {
+ public String userAuthHeader;
- return resource().path("oauth2").path("authorize").header(
- Attributes.AUTHORIZATION,
- HttpAuthorizationHandler.createBasicAuthorizationHeaderValue(
- "dory", "password"))
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
+ public OAuth2ControllerTest () throws KustvaktException {
+ userAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue("dory", "password");
}
@Test
public void testAuthorizeConfidentialClient () throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "code");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", confidentialClientId);
form.add("state", "thisIsMyState");
- ClientResponse response = requestAuthorization(form);
+ ClientResponse response =
+ requestAuthorizationCode(form, userAuthHeader);
assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
response.getStatus());
@@ -68,20 +61,9 @@
@Test
public void testAuthorizePublicClient () throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("response_type", "code");
- form.add("client_id", "8bIDtZnH6NvRkW2Fq");
- form.add("state", "thisIsMyState");
-
- ClientResponse response = requestAuthorization(form);
-
- assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
- response.getStatus());
- URI redirectUri = response.getLocation();
- MultiValueMap<String, String> params = UriComponentsBuilder
- .fromUri(redirectUri).build().getQueryParams();
- assertNotNull(params.getFirst("code"));
- assertEquals("thisIsMyState", params.getFirst("state"));
+ String code = requestAuthorizationCode(publicClientId, clientSecret,
+ null, userAuthHeader);
+ assertNotNull(code);
}
@Test
@@ -90,10 +72,11 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "code");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", confidentialClientId);
form.add("redirect_uri", redirectUri);
form.add("state", "thisIsMyState");
- ClientResponse response = requestAuthorization(form);
+ ClientResponse response =
+ requestAuthorizationCode(form, userAuthHeader);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -112,7 +95,8 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("state", "thisIsMyState");
// missing response_type
- ClientResponse response = requestAuthorization(form);
+ ClientResponse response =
+ requestAuthorizationCode(form, userAuthHeader);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -126,7 +110,7 @@
// missing client_id
form.add("response_type", "code");
- response = requestAuthorization(form);
+ response = requestAuthorizationCode(form, userAuthHeader);
entity = response.getEntity(String.class);
node = JsonUtils.readTree(entity);
assertEquals("Missing parameters: client_id",
@@ -139,7 +123,8 @@
form.add("response_type", "string");
form.add("state", "thisIsMyState");
- ClientResponse response = requestAuthorization(form);
+ ClientResponse response =
+ requestAuthorizationCode(form, userAuthHeader);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
String entity = response.getEntity(String.class);
@@ -155,11 +140,12 @@
public void testAuthorizeInvalidScope () throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("response_type", "code");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", confidentialClientId);
form.add("scope", "read_address");
form.add("state", "thisIsMyState");
- ClientResponse response = requestAuthorization(form);
+ ClientResponse response =
+ requestAuthorizationCode(form, userAuthHeader);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
URI location = response.getLocation();
@@ -171,65 +157,48 @@
assertEquals("thisIsMyState", params.getFirst("state"));
}
- private ClientResponse requestToken (MultivaluedMap<String, String> form)
- throws KustvaktException {
- return resource().path("oauth2").path("token")
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .header(HttpHeaders.CONTENT_TYPE,
- ContentType.APPLICATION_FORM_URLENCODED)
- .entity(form).post(ClientResponse.class);
- }
-
@Test
- public void testRequestTokenAuthorizationPublic () throws KustvaktException {
- String clientId = "8bIDtZnH6NvRkW2Fq";
- MultivaluedMap<String, String> authForm = new MultivaluedMapImpl();
- authForm.add("response_type", "code");
- authForm.add("client_id", clientId);
+ public void testRequestTokenAuthorizationPublic ()
+ throws KustvaktException {
+ String code = requestAuthorizationCode(publicClientId, "", null,
+ userAuthHeader);
- ClientResponse response = requestAuthorization(authForm);
- URI redirectUri = response.getLocation();
- MultiValueMap<String, String> params = UriComponentsBuilder
- .fromUri(redirectUri).build().getQueryParams();
- String code = params.get("code").get(0);
-
- MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
- tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", clientId);
- tokenForm.add("code", code);
-
- response = requestToken(tokenForm);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ publicClientId, clientSecret, code);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
-
+
String accessToken = node.at("/access_token").asText();
String refreshToken = node.at("/refresh_token").asText();
-
+
assertEquals(TokenType.BEARER.toString(),
node.at("/token_type").asText());
assertNotNull(node.at("/expires_in").asText());
-
- testRevokeTokenPublicClient(accessToken, clientId, "access_token");
-
- testRequestRefreshTokenInvalidScope(clientId, refreshToken);
- testRequestRefreshTokenPublicClient(clientId, refreshToken);
+
+ testRevokeTokenPublicClient(accessToken, publicClientId,
+ "access_token");
+
+ testRequestRefreshTokenInvalidScope(publicClientId, refreshToken);
+ testRequestRefreshTokenPublicClient(publicClientId, refreshToken);
testRequestRefreshTokenInvalidClient(refreshToken);
- testRequestRefreshTokenInvalidRefreshToken(clientId);
-
- testRevokeTokenPublicClient(refreshToken, clientId, "refresh_token");
- testRequestRefreshWithRevokedRefreshToken(clientId, refreshToken);
+ testRequestRefreshTokenInvalidRefreshToken(publicClientId);
+
+ testRevokeTokenPublicClient(refreshToken, publicClientId,
+ "refresh_token");
+ testRequestRefreshWithRevokedRefreshToken(publicClientId, refreshToken);
}
-
+
@Test
public void testRequestTokenAuthorizationConfidential ()
throws KustvaktException {
MultivaluedMap<String, String> authForm = new MultivaluedMapImpl();
authForm.add("response_type", "code");
- authForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ authForm.add("client_id", confidentialClientId);
authForm.add("scope", "search");
- ClientResponse response = requestAuthorization(authForm);
+ ClientResponse response =
+ requestAuthorizationCode(authForm, userAuthHeader);
URI redirectUri = response.getLocation();
MultivaluedMap<String, String> params =
UriComponent.decodeQuery(redirectUri, true);
@@ -238,13 +207,8 @@
assertEquals(scopes, "search");
- MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
- tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
- tokenForm.add("client_secret", "secret");
- tokenForm.add("code", code);
-
- response = requestToken(tokenForm);
+ response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, code);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
assertNotNull(node.at("/access_token").asText());
@@ -253,12 +217,13 @@
node.at("/token_type").asText());
assertNotNull(node.at("/expires_in").asText());
- testRequestTokenWithUsedAuthorization(tokenForm);
+ testRequestTokenWithUsedAuthorization(code);
}
- private void testRequestTokenWithUsedAuthorization (
- MultivaluedMap<String, String> form) throws KustvaktException {
- ClientResponse response = requestToken(form);
+ private void testRequestTokenWithUsedAuthorization (String code)
+ throws KustvaktException {
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, code);
String entity = response.getEntity(String.class);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -273,13 +238,8 @@
@Test
public void testRequestTokenInvalidAuthorizationCode ()
throws KustvaktException {
- MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
- tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
- tokenForm.add("client_secret", "secret");
- tokenForm.add("code", "blahblah");
-
- ClientResponse response = requestToken(tokenForm);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, "blahblah");
String entity = response.getEntity(String.class);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -292,14 +252,15 @@
@Test
public void testRequestTokenAuthorizationReplyAttack ()
throws KustvaktException {
- String uri = "https://korap.ids-mannheim.de/confidential/redirect";
+ String uri = "https://third.party.com/confidential/redirect";
MultivaluedMap<String, String> authForm = new MultivaluedMapImpl();
authForm.add("response_type", "code");
- authForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ authForm.add("client_id", confidentialClientId);
authForm.add("scope", "search");
authForm.add("redirect_uri", uri);
- ClientResponse response = requestAuthorization(authForm);
+ ClientResponse response =
+ requestAuthorizationCode(authForm, userAuthHeader);
URI redirectUri = response.getLocation();
MultivaluedMap<String, String> params =
UriComponent.decodeQuery(redirectUri, true);
@@ -312,13 +273,8 @@
private void testRequestTokenAuthorizationInvalidClient (String code)
throws KustvaktException {
- MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
- tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
- tokenForm.add("client_secret", "blah");
- tokenForm.add("code", code);
-
- ClientResponse response = requestToken(tokenForm);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, "wrong_secret", code);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
assertEquals(OAuth2Error.INVALID_CLIENT, node.at("/error").asText());
@@ -328,7 +284,7 @@
throws KustvaktException {
MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ tokenForm.add("client_id", confidentialClientId);
tokenForm.add("client_secret", "secret");
tokenForm.add("code", code);
tokenForm.add("redirect_uri", "https://blahblah.com");
@@ -343,7 +299,7 @@
throws KustvaktException {
MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
tokenForm.add("grant_type", "authorization_code");
- tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ tokenForm.add("client_id", confidentialClientId);
tokenForm.add("client_secret", "secret");
tokenForm.add("code", code);
tokenForm.add("redirect_uri", uri);
@@ -357,20 +313,15 @@
node.at("/error_description").asText());
}
-
@Test
- public void testRequestTokenPasswordGrantConfidential ()
+ public void testRequestTokenPasswordGrantConfidentialSuper ()
throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
- form.add("client_secret", "secret");
- form.add("username", "dory");
- form.add("password", "password");
+ ClientResponse response =
+ requestTokenWithPassword(superClientId, clientSecret);
- ClientResponse response = requestToken(form);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
String entity = response.getEntity(String.class);
-
JsonNode node = JsonUtils.readTree(entity);
assertNotNull(node.at("/access_token").asText());
assertEquals(TokenType.BEARER.toString(),
@@ -379,11 +330,41 @@
}
@Test
+ public void testRequestTokenPasswordGrantConfidentialNonSuper ()
+ throws KustvaktException {
+ ClientResponse response =
+ requestTokenWithPassword(confidentialClientId, clientSecret);
+ String entity = response.getEntity(String.class);
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(entity);
+ assertEquals(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT,
+ node.at("/error").asText());
+ assertEquals("Password grant is not allowed for third party clients",
+ node.at("/error_description").asText());
+ }
+
+ @Test
+ public void testRequestTokenPasswordGrantPublic ()
+ throws KustvaktException {
+ ClientResponse response = requestTokenWithPassword(publicClientId, "");
+ String entity = response.getEntity(String.class);
+
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(entity);
+ assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
+ node.at("/error").asText());
+ assertEquals("Password grant is not allowed for third party clients",
+ node.at("/error_description").asText());
+ }
+
+ @Test
public void testRequestTokenPasswordGrantAuthorizationHeader ()
throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", "password");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", superClientId);
form.add("username", "dory");
form.add("password", "password");
@@ -435,14 +416,8 @@
@Test
public void testRequestTokenPasswordGrantMissingClientSecret ()
throws KustvaktException {
-
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("username", "dory");
- form.add("password", "password");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
-
- ClientResponse response = requestToken(form);
+ ClientResponse response =
+ requestTokenWithPassword(confidentialClientId, "");
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
String entity = response.getEntity(String.class);
@@ -456,13 +431,7 @@
@Test
public void testRequestTokenPasswordGrantMissingClientId ()
throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("username", "dory");
- form.add("password", "password");
- form.add("client_secret", "secret");
-
- ClientResponse response = requestToken(form);
+ ClientResponse response = requestTokenWithPassword(null, clientSecret);
String entity = response.getEntity(String.class);
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -474,56 +443,12 @@
}
@Test
- public void testRequestTokenPasswordGrantPublic ()
- throws KustvaktException {
- String clientId = "8bIDtZnH6NvRkW2Fq";
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("username", "dory");
- form.add("password", "password");
- form.add("client_id", clientId);
-
- ClientResponse response = requestToken(form);
- String entity = response.getEntity(String.class);
-
- assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
-
- JsonNode node = JsonUtils.readTree(entity);
- assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
- node.at("/error").asText());
- assertEquals("Password grant is not allowed for third party clients",
- node.at("/error_description").asText());
- }
-
- @Test
- public void testRequestTokenPasswordGrantConfidentialNonSuper ()
- throws KustvaktException {
- MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
- form.add("username", "dory");
- form.add("password", "password");
- // confidential non-super
- form.add("client_id", "9aHsGW6QflV13ixNpez");
- form.add("client_secret", "secret");
-
- ClientResponse response = requestToken(form);
- String entity = response.getEntity(String.class);
- assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
-
- JsonNode node = JsonUtils.readTree(entity);
- assertEquals(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT,
- node.at("/error").asText());
- assertEquals("Password grant is not allowed for third party clients",
- node.at("/error_description").asText());
- }
-
- @Test
public void testRequestTokenClientCredentialsGrant ()
throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", "client_credentials");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", confidentialClientId);
form.add("client_secret", "secret");
ClientResponse response = requestToken(form);
String entity = response.getEntity(String.class);
@@ -548,7 +473,7 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", "client_credentials");
- form.add("client_id", "8bIDtZnH6NvRkW2Fq");
+ form.add("client_id", publicClientId);
form.add("client_secret", "");
ClientResponse response = requestToken(form);
@@ -567,7 +492,7 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", "client_credentials");
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", confidentialClientId);
form.add("client_secret", "secret");
form.add("scope", "preferred_username client_info");
@@ -716,8 +641,8 @@
assertEquals(OAuth2Error.INVALID_GRANT, node.at("/error").asText());
}
- private void testRevokeTokenPublicClient (String token,
- String clientId, String tokenType) {
+ private void testRevokeTokenPublicClient (String token, String clientId,
+ String tokenType) {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("token_type", tokenType);
form.add("token", token);
@@ -727,7 +652,7 @@
.header(HttpHeaders.CONTENT_TYPE,
ContentType.APPLICATION_FORM_URLENCODED)
.entity(form).post(ClientResponse.class);
-
+
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
new file mode 100644
index 0000000..fb85f17
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
@@ -0,0 +1,152 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.http.entity.ContentType;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+/** Provides common methods and variables for OAuth2 tests,
+ * and does not run any test.
+ *
+ * @author margaretha
+ *
+ */
+public class OAuth2TestBase extends SpringJerseyTest {
+
+ protected String publicClientId = "8bIDtZnH6NvRkW2Fq";
+ protected String confidentialClientId = "9aHsGW6QflV13ixNpez";
+ protected String superClientId = "fCBbQkAyYzI4NzUxMg";
+ protected String clientSecret = "secret";
+
+ public ClientResponse requestAuthorizationCode (
+ MultivaluedMap<String, String> form, String authHeader)
+ throws KustvaktException {
+
+ return resource().path("oauth2").path("authorize")
+ .header(Attributes.AUTHORIZATION, authHeader)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+ }
+
+ public String requestAuthorizationCode (String clientId,
+ String clientSecret, String scope, String authHeader)
+ throws KustvaktException {
+
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("response_type", "code");
+ form.add("client_id", clientId);
+ form.add("client_secret", clientSecret);
+ if (scope != null) {
+ form.add("scope", scope);
+ }
+
+ ClientResponse response = requestAuthorizationCode(form, authHeader);
+ assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
+ response.getStatus());
+ URI redirectUri = response.getLocation();
+
+ MultiValueMap<String, String> params = UriComponentsBuilder
+ .fromUri(redirectUri).build().getQueryParams();
+ return params.getFirst("code");
+ }
+
+ public ClientResponse requestToken (MultivaluedMap<String, String> form)
+ throws KustvaktException {
+ return resource().path("oauth2").path("token")
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+ }
+
+ // client credentials as form params
+ public ClientResponse requestTokenWithAuthorizationCodeAndForm (
+ String clientId, String clientSecret, String code)
+ throws KustvaktException {
+
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("grant_type", "authorization_code");
+ form.add("client_id", clientId);
+ form.add("client_secret", clientSecret);
+ form.add("code", code);
+
+ return resource().path("oauth2").path("token")
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+ }
+
+ // client credentials in authorization header
+ public JsonNode requestTokenWithAuthorizationCodeAndHeader (String clientId,
+ String code, String authHeader) throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("grant_type", "authorization_code");
+ form.add("client_id", clientId);
+ form.add("code", code);
+
+ ClientResponse response = resource().path("oauth2").path("token")
+ .header(Attributes.AUTHORIZATION, authHeader)
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+
+ String entity = response.getEntity(String.class);
+ return JsonUtils.readTree(entity);
+ }
+
+ public ClientResponse requestTokenWithPassword (String clientId,
+ String clientSecret) throws KustvaktException {
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("grant_type", "password");
+ form.add("client_id", clientId);
+ form.add("client_secret", clientSecret);
+ form.add("username", "dory");
+ form.add("password", "password");
+
+ return requestToken(form);
+ }
+
+ public void updateClientPrivilege (MultivaluedMap<String, String> form)
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+ ClientResponse response = resource().path("oauth2").path("client")
+ .path("privilege")
+ .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue("admin", "pass"))
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ }
+
+ public ClientResponse searchWithAccessToken (String accessToken) {
+ return resource().path("search").queryParam("q", "Wasser")
+ .queryParam("ql", "poliqarp")
+ .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .get(ClientResponse.class);
+ }
+
+}