Added the list-user-client controller.
Change-Id: I65b6d392da59d1f3412b28ae81ae0bec321d2077
diff --git a/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java b/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
index 5cd1293..9993541 100644
--- a/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
+++ b/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
@@ -8,6 +8,8 @@
OPENID,
AUTHORIZE,
+ LIST_USER_CLIENT,
+
CLIENT_INFO,
REGISTER_CLIENT,
DEREGISTER_CLIENT,
diff --git a/full/Changes b/full/Changes
index b111732..1df0b92 100644
--- a/full/Changes
+++ b/full/Changes
@@ -7,6 +7,8 @@
28/11/2018
- Updated NamedVCLoader to delete existing VC in DB (margaretha)
- Handled storing cached VC with VC reference (margaretha)
+29/11/2018
+ - Added the list-user-client controller (margaretha)
# version 0.61.3
17/10/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessScopeDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessScopeDao.java
index de0cfac..a714420 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessScopeDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/AccessScopeDao.java
@@ -15,7 +15,6 @@
import de.ids_mannheim.korap.constant.OAuth2Scope;
import de.ids_mannheim.korap.oauth2.entity.AccessScope;
-import de.ids_mannheim.korap.oauth2.entity.AccessScope;
@Repository
@Transactional
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
index 31fa2b3..444659e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
@@ -1,22 +1,32 @@
package de.ids_mannheim.korap.oauth2.dao;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.List;
+
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ListJoin;
+import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
+import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
import de.ids_mannheim.korap.oauth2.entity.OAuth2ClientUrl;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client_;
+import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
+import de.ids_mannheim.korap.oauth2.entity.RefreshToken_;
import de.ids_mannheim.korap.utils.ParameterChecker;
@Transactional
@@ -97,4 +107,29 @@
client = entityManager.merge(client);
}
+ public List<OAuth2Client> retrieveUserClients (String username)
+ throws KustvaktException {
+ ParameterChecker.checkStringValue(username, "username");
+
+ CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+ CriteriaQuery<OAuth2Client> query =
+ builder.createQuery(OAuth2Client.class);
+
+ Root<OAuth2Client> client = query.from(OAuth2Client.class);
+ ListJoin<OAuth2Client, RefreshToken> refreshToken =
+ client.join(OAuth2Client_.refreshTokens);
+ Predicate condition = builder.and(
+ builder.equal(refreshToken.get(RefreshToken_.userId), username),
+ builder.equal(refreshToken.get(RefreshToken_.isRevoked), false),
+ builder.greaterThan(
+ refreshToken
+ .<ZonedDateTime> get(RefreshToken_.expiryDate),
+ ZonedDateTime
+ .now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE))));
+ query.select(client);
+ query.where(condition);
+ TypedQuery<OAuth2Client> q = entityManager.createQuery(query);
+ return q.getResultList();
+ }
+
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/RefreshTokenDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/RefreshTokenDao.java
index e98c627..8ee798b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/RefreshTokenDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/RefreshTokenDao.java
@@ -8,8 +8,10 @@
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
@@ -20,6 +22,8 @@
import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.oauth2.entity.AccessScope;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client_;
import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
import de.ids_mannheim.korap.oauth2.entity.RefreshToken_;
import de.ids_mannheim.korap.utils.ParameterChecker;
@@ -32,6 +36,8 @@
private EntityManager entityManager;
@Autowired
private FullConfiguration config;
+ @Autowired
+ private OAuth2ClientDao clientDao;
public RefreshToken storeRefreshToken (String refreshToken, String userId,
ZonedDateTime userAuthenticationTime, String clientId,
@@ -43,12 +49,13 @@
ZonedDateTime now =
ZonedDateTime.now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE));
+ OAuth2Client client = clientDao.retrieveClientById(clientId);
RefreshToken token = new RefreshToken();
token.setToken(refreshToken);
token.setUserId(userId);
token.setUserAuthenticationTime(userAuthenticationTime);
- token.setClientId(clientId);
+ token.setClient(client);
token.setCreatedDate(now);
token.setExpiryDate(now.plusSeconds(config.getRefreshTokenExpiry()));
token.setScopes(scopes);
@@ -63,13 +70,14 @@
CriteriaQuery<RefreshToken> query =
builder.createQuery(RefreshToken.class);
Root<RefreshToken> root = query.from(RefreshToken.class);
+ root.fetch(RefreshToken_.client);
+
query.select(root);
query.where(builder.equal(root.get(RefreshToken_.token), token));
Query q = entityManager.createQuery(query);
return (RefreshToken) q.getSingleResult();
}
- @SuppressWarnings("unchecked")
public List<RefreshToken> retrieveRefreshTokenByClientId (String clientId)
throws KustvaktException {
ParameterChecker.checkStringValue(clientId, "client_id");
@@ -78,9 +86,11 @@
CriteriaQuery<RefreshToken> query =
builder.createQuery(RefreshToken.class);
Root<RefreshToken> root = query.from(RefreshToken.class);
+ Join<RefreshToken, OAuth2Client> client =
+ root.join(RefreshToken_.client);
query.select(root);
- query.where(builder.equal(root.get(RefreshToken_.clientId), clientId));
- Query q = entityManager.createQuery(query);
+ query.where(builder.equal(client.get(OAuth2Client_.id), clientId));
+ TypedQuery<RefreshToken> q = entityManager.createQuery(query);
return q.getResultList();
}
@@ -91,4 +101,28 @@
token = entityManager.merge(token);
return token;
}
+
+ // public List<RefreshToken> retrieveRefreshTokenByUser (String
+ // username)
+ // throws KustvaktException {
+ // ParameterChecker.checkStringValue(username, "username");
+ //
+ // CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+ // CriteriaQuery<RefreshToken> query =
+ // builder.createQuery(RefreshToken.class);
+ //
+ // Root<RefreshToken> root = query.from(RefreshToken.class);
+ // Predicate condition = builder.and(
+ // builder.equal(root.get(RefreshToken_.userId), username),
+ // builder.equal(root.get(RefreshToken_.isRevoked), false),
+ // builder.greaterThan(
+ // root.<ZonedDateTime> get(RefreshToken_.expiryDate),
+ // ZonedDateTime
+ // .now(ZoneId.of(Attributes.DEFAULT_TIME_ZONE)))
+ // );
+ // query.select(root);
+ // query.where(condition);
+ // TypedQuery<RefreshToken> q = entityManager.createQuery(query);
+ // return q.getResultList();
+ // }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2UserClientDto.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2UserClientDto.java
new file mode 100644
index 0000000..02ab148
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2UserClientDto.java
@@ -0,0 +1,20 @@
+package de.ids_mannheim.korap.oauth2.dto;
+
+public class OAuth2UserClientDto {
+
+ private String clientId;
+ private String clientName;
+
+ public String getClientName () {
+ return clientName;
+ }
+ public void setClientName (String clientName) {
+ this.clientName = clientName;
+ }
+ public String getClientId () {
+ return clientId;
+ }
+ public void setClientId (String clientId) {
+ this.clientId = clientId;
+ }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
index 09c6e35..8023e32 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
@@ -1,5 +1,7 @@
package de.ids_mannheim.korap.oauth2.entity;
+import java.util.List;
+
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -8,6 +10,7 @@
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@@ -19,7 +22,7 @@
*/
@Entity
@Table(name = "oauth2_client")
-public class OAuth2Client {
+public class OAuth2Client implements Comparable<OAuth2Client>{
@Id
private String id;
@@ -40,6 +43,9 @@
@JoinColumn(name = "url_id")
private OAuth2ClientUrl clientUrl;
+ @OneToMany(fetch = FetchType.LAZY, mappedBy = "client")
+ private List<RefreshToken> refreshTokens;
+
@Override
public String toString () {
return "id=" + id + ", name=" + name + ", secret=" + secret + ", type="
@@ -119,4 +125,9 @@
public void setClientUrl (OAuth2ClientUrl clientUrl) {
this.clientUrl = clientUrl;
}
+
+ @Override
+ public int compareTo (OAuth2Client o) {
+ return this.getName().compareTo(o.getName());
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/RefreshToken.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/RefreshToken.java
index a43a493..a60aef5 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/RefreshToken.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/RefreshToken.java
@@ -12,6 +12,7 @@
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@@ -30,8 +31,8 @@
private ZonedDateTime expiryDate;
@Column(name = "user_id")
private String userId;
- @Column(name = "client_id")
- private String clientId;
+// @Column(name = "client_id")
+// private String clientId;
@Column(name = "user_auth_time", updatable = false)
private ZonedDateTime userAuthenticationTime;
@Column(name = "is_revoked")
@@ -39,6 +40,10 @@
@OneToMany(fetch = FetchType.EAGER, mappedBy = "refreshToken")
private Set<AccessToken> accessTokens;
+
+ @ManyToOne(fetch=FetchType.LAZY)
+ @JoinColumn(name="client")
+ private OAuth2Client client;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "oauth2_refresh_token_scope",
@@ -82,14 +87,6 @@
this.userId = userId;
}
- public String getClientId () {
- return clientId;
- }
-
- public void setClientId (String clientId) {
- this.clientId = clientId;
- }
-
public ZonedDateTime getUserAuthenticationTime () {
return userAuthenticationTime;
}
@@ -123,4 +120,12 @@
this.scopes = scopes;
}
+ public OAuth2Client getClient () {
+ return client;
+ }
+
+ public void setClient (OAuth2Client client) {
+ this.client = client;
+ }
+
}
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 6bf3b39..7b4ac81 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
@@ -120,7 +120,7 @@
"Refresh token is not found", OAuth2Error.INVALID_GRANT);
}
- if (!clientId.equals(refreshToken.getClientId())) {
+ if (!clientId.equals(refreshToken.getClient().getId())) {
throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
"Client " + clientId + "is not authorized",
OAuth2Error.INVALID_CLIENT);
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 47dffe3..23b8267 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
@@ -5,6 +5,8 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import org.apache.commons.validator.routines.UrlValidator;
@@ -25,6 +27,7 @@
import de.ids_mannheim.korap.oauth2.dao.RefreshTokenDao;
import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientInfoDto;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2UserClientDto;
import de.ids_mannheim.korap.oauth2.entity.AccessToken;
import de.ids_mannheim.korap.oauth2.entity.Authorization;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
@@ -337,4 +340,36 @@
"Unauthorized operation for user: " + username, username);
}
}
+
+ public OAuth2Client retrieveClient (String clientId)
+ throws KustvaktException {
+ return clientDao.retrieveClientById(clientId);
+ }
+
+ public List<OAuth2Client> retrieveUserClients (String username)
+ throws KustvaktException {
+ return clientDao.retrieveUserClients(username);
+ }
+
+ public List<OAuth2UserClientDto> listUserClients (String username,
+ String clientId, String clientSecret) throws KustvaktException {
+ OAuth2Client client = authenticateClient(clientId, clientSecret);
+ if (!client.isSuper()) {
+ throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
+ "Only super client is allowed to list user clients.",
+ OAuth2Error.UNAUTHORIZED_CLIENT);
+ }
+ List<OAuth2Client> userClients = retrieveUserClients(username);
+ Collections.sort(userClients);
+
+ List<OAuth2UserClientDto> dtoList = new ArrayList<>(userClients.size());
+ for (OAuth2Client uc : userClients) {
+ if (uc.isSuper()) continue;
+ OAuth2UserClientDto dto = new OAuth2UserClientDto();
+ dto.setClientId(uc.getId());
+ dto.setClientName(uc.getName());
+ dtoList.add(dto);
+ }
+ return dtoList;
+ }
}
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 ca7e168..02b190f 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
@@ -1,5 +1,7 @@
package de.ids_mannheim.korap.web.controller;
+import java.util.List;
+
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
@@ -22,6 +24,7 @@
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientInfoDto;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2UserClientDto;
import de.ids_mannheim.korap.oauth2.service.OAuth2ClientService;
import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
@@ -55,7 +58,8 @@
*/
@Controller
@Path("{version}/oauth2/client")
-@ResourceFilters({APIVersionFilter.class, AuthenticationFilter.class, BlockingFilter.class })
+@ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
+ BlockingFilter.class })
public class OAuthClientController {
@Autowired
@@ -180,7 +184,8 @@
* authorization codes are invalidated.
*
* @param securityContext
- * @param clientId OAuth2 client id
+ * @param clientId
+ * OAuth2 client id
* @param super
* true indicating super client, false otherwise
* @return Response status OK, if successful
@@ -222,4 +227,43 @@
throw responseHandler.throwit(e);
}
}
+
+ /**
+ * Lists user clients having refresh tokens. This service is not
+ * part of the OAuth2 specification. It is intended to facilitate
+ * users revoking any suspicious and misused access or refresh
+ * tokens.
+ *
+ * Only super clients are allowed to use this service. It requires
+ * user and client authentications.
+ *
+ * @param context
+ * @return a list of clients having refresh tokens of the
+ * given user
+ */
+ @POST
+ @Path("list")
+ @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public List<OAuth2UserClientDto> listUserApp (
+ @Context SecurityContext context,
+ @FormParam("client_id") String clientId,
+ @FormParam("client_secret") String clientSecret) {
+
+ TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+ String username = tokenContext.getUsername();
+
+ try {
+ scopeService.verifyScope(tokenContext,
+ OAuth2Scope.LIST_USER_CLIENT);
+
+ return clientService.listUserClients(username, clientId,
+ clientSecret);
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+
}
diff --git a/full/src/main/resources/db/sqlite/V1.4__oauth2_tables.sql b/full/src/main/resources/db/sqlite/V1.4__oauth2_tables.sql
index e0c06d6..fe0123c 100644
--- a/full/src/main/resources/db/sqlite/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/sqlite/V1.4__oauth2_tables.sql
@@ -62,11 +62,11 @@
token VARCHAR(255) NOT NULL,
user_id VARCHAR(100) DEFAULT NULL,
user_auth_time TIMESTAMP NOT NULL,
- client_id VARCHAR(100) DEFAULT NULL,
created_date TIMESTAMP NOT NULL,
expiry_date TIMESTAMP NULL,
is_revoked BOOLEAN DEFAULT 0,
- FOREIGN KEY (client_id)
+ client VARCHAR(100) DEFAULT NULL,
+ FOREIGN KEY (client)
REFERENCES oauth2_client(id)
);
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 674a5e6..7697db7 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
@@ -42,7 +42,7 @@
@Test
public void testScopeWithSuperClient () throws KustvaktException {
ClientResponse response =
- requestTokenWithPassword(superClientId, clientSecret);
+ requestTokenWithDoryPassword(superClientId, clientSecret);
JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
assertEquals("all", node.at("/scope").asText());
@@ -261,7 +261,7 @@
public void testRequestAuthorizationWithBearerToken ()
throws KustvaktException {
ClientResponse response =
- requestTokenWithPassword(superClientId, clientSecret);
+ requestTokenWithDoryPassword(superClientId, clientSecret);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
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 1c59d76..a87e83b 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
@@ -67,7 +67,8 @@
json.setRedirectURI("https://example.client.com/redirect");
json.setDescription("This is a confidential test client.");
- return resource().path(API_VERSION).path("oauth2").path("client").path("register")
+ return resource().path(API_VERSION).path("oauth2").path("client")
+ .path("register")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -78,8 +79,8 @@
private JsonNode retrieveClientInfo (String clientId, String username)
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("info").path(clientId)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("info").path(clientId)
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.get(ClientResponse.class);
@@ -128,8 +129,8 @@
json.setRedirectURI("https://test.public.client.com/redirect");
json.setDescription("This is a public test client.");
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("register")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("register")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -155,8 +156,8 @@
json.setType(OAuth2ClientType.PUBLIC);
json.setDescription("This is a desktop test client.");
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("register")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("register")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -182,8 +183,8 @@
String code =
requestAuthorizationCode(clientId, "", null, userAuthHeader);
- ClientResponse response = requestTokenWithAuthorizationCodeAndForm(clientId,
- clientSecret, code);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ clientId, clientSecret, code);
JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
String accessToken = node.at("/access_token").asText();
@@ -213,8 +214,9 @@
String clientId) throws UniformInterfaceException,
ClientHandlerException, KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister").path(clientId).delete(ClientResponse.class);
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister").path(clientId)
+ .delete(ClientResponse.class);
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
@@ -228,8 +230,8 @@
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.delete(ClientResponse.class);
@@ -241,8 +243,8 @@
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister").path(clientId)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister").path(clientId)
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.delete(ClientResponse.class);
@@ -257,8 +259,8 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("client_secret", clientSecret);
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister").path(clientId)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister").path(clientId)
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -271,8 +273,8 @@
private void testDeregisterConfidentialClientMissingSecret (String clientId)
throws KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister").path(clientId)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister").path(clientId)
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -295,8 +297,8 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("client_secret", clientSecret);
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("deregister").path(clientId)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("deregister").path(clientId)
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -320,8 +322,8 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("client_id", clientId);
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("reset")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("reset")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -343,8 +345,8 @@
form.add("client_id", clientId);
form.add("client_secret", clientSecret);
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("reset")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("reset")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -382,7 +384,7 @@
testAccessTokenAfterUpgradingClient(clientId, accessToken);
testAccessTokenAfterDegradingSuperClient(clientId, accessToken);
-
+
testDeregisterConfidentialClient(clientId, clientSecret);
}
@@ -398,9 +400,11 @@
assertTrue(node.at("/isSuper").asBoolean());
// list vc
- ClientResponse response = resource().path(API_VERSION).path("vc").path("list")
- .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
- .get(ClientResponse.class);
+ ClientResponse response =
+ resource().path(API_VERSION).path("vc").path("list")
+ .header(Attributes.AUTHORIZATION,
+ "Bearer " + accessToken)
+ .get(ClientResponse.class);
assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
response.getStatus());
@@ -410,7 +414,7 @@
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());
@@ -421,7 +425,7 @@
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());
@@ -429,7 +433,7 @@
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,
@@ -437,4 +441,51 @@
assertEquals("Access token has been revoked",
node.at("/errors/0/1").asText());
}
+
+ @Test
+ public void testListUserClients () throws KustvaktException {
+ String username = "pearl";
+ String password = "pwd";
+ userAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(username, password);
+
+ // super client
+ ClientResponse response = requestTokenWithPassword(superClientId,
+ clientSecret, username, password);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ // client 1
+ String code = requestAuthorizationCode(publicClientId, clientSecret,
+ null, userAuthHeader);
+ response = requestTokenWithAuthorizationCodeAndForm(publicClientId, "",
+ code);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ // client 2
+ code = requestAuthorizationCode(confidentialClientId, clientSecret,
+ null, userAuthHeader);
+ response = requestTokenWithAuthorizationCodeAndForm(
+ confidentialClientId, clientSecret, code);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("client_id", superClientId);
+ form.add("client_secret", clientSecret);
+
+ response = resource().path(API_VERSION).path("oauth2").path("client")
+ .path("list").header(Attributes.AUTHORIZATION, userAuthHeader)
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ String entity = response.getEntity(String.class);
+ JsonNode node = JsonUtils.readTree(entity);
+
+ assertEquals(2, node.size());
+ assertEquals(confidentialClientId, node.at("/0/clientId").asText());
+ assertEquals(publicClientId, node.at("/1/clientId").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 945e9d0..e454762 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
@@ -322,7 +322,7 @@
public void testRequestTokenPasswordGrantConfidentialSuper ()
throws KustvaktException {
ClientResponse response =
- requestTokenWithPassword(superClientId, clientSecret);
+ requestTokenWithDoryPassword(superClientId, clientSecret);
assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -338,7 +338,7 @@
public void testRequestTokenPasswordGrantConfidentialNonSuper ()
throws KustvaktException {
ClientResponse response =
- requestTokenWithPassword(confidentialClientId, clientSecret);
+ requestTokenWithDoryPassword(confidentialClientId, clientSecret);
String entity = response.getEntity(String.class);
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
@@ -352,7 +352,7 @@
@Test
public void testRequestTokenPasswordGrantPublic ()
throws KustvaktException {
- ClientResponse response = requestTokenWithPassword(publicClientId, "");
+ ClientResponse response = requestTokenWithDoryPassword(publicClientId, "");
String entity = response.getEntity(String.class);
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
@@ -422,7 +422,7 @@
public void testRequestTokenPasswordGrantMissingClientSecret ()
throws KustvaktException {
ClientResponse response =
- requestTokenWithPassword(confidentialClientId, "");
+ requestTokenWithDoryPassword(confidentialClientId, "");
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
String entity = response.getEntity(String.class);
@@ -436,7 +436,7 @@
@Test
public void testRequestTokenPasswordGrantMissingClientId ()
throws KustvaktException {
- ClientResponse response = requestTokenWithPassword(null, clientSecret);
+ ClientResponse response = requestTokenWithDoryPassword(null, clientSecret);
String entity = response.getEntity(String.class);
assertEquals(Status.BAD_REQUEST.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
index bf068bf..42318bc 100644
--- 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
@@ -24,8 +24,9 @@
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.
+/**
+ * Provides common methods and variables for OAuth2 tests,
+ * and does not run any test.
*
* @author margaretha
*
@@ -105,8 +106,8 @@
form.add("client_id", clientId);
form.add("code", code);
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("token")
- .header(Attributes.AUTHORIZATION, authHeader)
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("token").header(Attributes.AUTHORIZATION, authHeader)
.header(HttpHeaders.CONTENT_TYPE,
ContentType.APPLICATION_FORM_URLENCODED)
.entity(form).post(ClientResponse.class);
@@ -115,14 +116,21 @@
return JsonUtils.readTree(entity);
}
- public ClientResponse requestTokenWithPassword (String clientId,
+ public ClientResponse requestTokenWithDoryPassword (String clientId,
String clientSecret) throws KustvaktException {
+ return requestTokenWithPassword(clientId, clientSecret, "dory",
+ "password");
+ }
+
+ public ClientResponse requestTokenWithPassword (String clientId,
+ String clientSecret, String username, String password)
+ 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");
+ form.add("username", username);
+ form.add("password", password);
return requestToken(form);
}
@@ -130,8 +138,8 @@
public void updateClientPrivilege (MultivaluedMap<String, String> form)
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2").path("client")
- .path("privilege")
+ ClientResponse response = resource().path(API_VERSION).path("oauth2")
+ .path("client").path("privilege")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue("admin", "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -140,10 +148,10 @@
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
-
+
public ClientResponse searchWithAccessToken (String accessToken) {
- return resource().path(API_VERSION).path("search").queryParam("q", "Wasser")
- .queryParam("ql", "poliqarp")
+ return resource().path(API_VERSION).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);