Implemented OAuth2 client info controller, super clients and unlimited
authorization scopes. Enabled using Bearer tokens as user authentication
methods for many controllers including OAuth2 controllers.
Change-Id: I1043164acbe49501210a6fca7f4531d110eb81a5
diff --git a/full/Changes b/full/Changes
index 18e2c34..81f9b88 100644
--- a/full/Changes
+++ b/full/Changes
@@ -7,14 +7,19 @@
- Implemented OAuth2 revoke token (margaretha)
- Updated OAuth2 refresh token implementation (margaretha)
14/08/2018
- - Disallow OAuth2 access token (type Bearer) usage for authentication
- in OAuth2 controllers (margaretha)
- Implemented revoke all OAuth2 access tokens and authorization codes of client
users when deregistering/deleting a client (margaretha)
- Fixed update OAuth2 access token (margaretha)
- Implemented reset client secret (margaretha)
- Fixed revoking latest access token when refreshing OAuth2 access token (margaretha)
-
+15/08/2018
+ - Implemented OAuth2 client info controller (margaretha)
+ - Implemented update OAuth2 client privilege controller for admins (margaretha)
+ - Implemented unlimited authorization scope for super clients with OAuth2 password grant (margaretha)
+ - 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)
+
# version 0.60.5
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/Initializator.java b/full/src/main/java/de/ids_mannheim/korap/config/Initializator.java
index 2d7c285..286195c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/Initializator.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/Initializator.java
@@ -1,8 +1,7 @@
package de.ids_mannheim.korap.config;
import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.EnumSet;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,11 +34,7 @@
}
private void setInitialAccessScope () {
- OAuth2Scope[] enums = OAuth2Scope.values();
- Set<String> scopes = new HashSet<>(enums.length);
- for (OAuth2Scope s : enums) {
- scopes.add(s.toString());
- }
+ EnumSet<OAuth2Scope> scopes = EnumSet.allOf(OAuth2Scope.class);
accessScopeDao.storeAccessScopes(scopes);
}
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/constant/OAuth2Scope.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/constant/OAuth2Scope.java
index 7e6c973..c44cc53 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/constant/OAuth2Scope.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/constant/OAuth2Scope.java
@@ -1,8 +1,40 @@
package de.ids_mannheim.korap.oauth2.constant;
public enum OAuth2Scope {
-
- OPENID, SEARCH, SERIALIZE_QUERY, MATCH_INFO, CREATE_VC, LIST_VC, EDIT_VC, VC_INFO, CLIENT_INFO;
+
+ ALL,
+ ADMIN,
+
+ OPENID,
+ AUTHORIZE,
+
+ CLIENT_INFO,
+ REGISTER_CLIENT,
+ DEREGISTER_CLIENT,
+ RESET_CLIENT_SECRET,
+
+ SEARCH,
+ SERIALIZE_QUERY,
+ MATCH_INFO,
+
+ USER_GROUP_INFO,
+ CREATE_USER_GROUP,
+ DELETE_USER_GROUP,
+
+ DELETE_USER_GROUP_MEMBER,
+ ADD_USER_GROUP_MEMBER,
+
+ ADD_USER_GROUP_MEMBER_ROLE,
+ DELETE_USER_GROUP_MEMBER_ROLE,
+
+ CREATE_VC,
+ VC_INFO,
+ EDIT_VC,
+ DELETE_VC,
+
+ SHARE_VC,
+ DELETE_VC_ACCESS,
+ VC_ACCESS_INFO;
@Override
public String toString () {
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 a94b506..aa158a3 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
@@ -13,6 +13,7 @@
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
import de.ids_mannheim.korap.oauth2.entity.AccessScope;
@Repository
@@ -33,10 +34,10 @@
return q.getResultList();
}
- public void storeAccessScopes (Set<String> scopes) {
+ public void storeAccessScopes (Set<OAuth2Scope> scopes) {
List<AccessScope> existingScopes = retrieveAccessScopes();
AccessScope newScope;
- for (String scope : scopes) {
+ for (OAuth2Scope scope : scopes) {
newScope = new AccessScope(scope);
if (!existingScopes.contains(newScope)) {
entityManager.persist(newScope);
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 2b8a2eb..31fa2b3 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
@@ -27,9 +27,9 @@
private EntityManager entityManager;
public void registerClient (String id, String secretHashcode, String name,
- OAuth2ClientType type, boolean isNative, String url,
- int urlHashCode, String redirectURI, String registeredBy,
- String description) throws KustvaktException {
+ OAuth2ClientType type, String url, int urlHashCode,
+ String redirectURI, String registeredBy, String description)
+ throws KustvaktException {
ParameterChecker.checkStringValue(id, "client id");
ParameterChecker.checkStringValue(name, "client name");
ParameterChecker.checkObjectValue(type, "client type");
@@ -44,7 +44,6 @@
client.setName(name);
client.setSecret(secretHashcode);
client.setType(type);
- client.setNative(isNative);
if (urlHashCode != 0) {
OAuth2ClientUrl clientUrl = new OAuth2ClientUrl();
clientUrl.setUrl(url);
@@ -84,7 +83,8 @@
}
}
- public void deregisterClient (OAuth2Client client) throws KustvaktException {
+ public void deregisterClient (OAuth2Client client)
+ throws KustvaktException {
ParameterChecker.checkObjectValue(client, "client");
if (!entityManager.contains(client)) {
client = entityManager.merge(client);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/OAuth2ClientDto.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientDto.java
similarity index 94%
rename from full/src/main/java/de/ids_mannheim/korap/dto/OAuth2ClientDto.java
rename to full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientDto.java
index b714404..3f6199b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/OAuth2ClientDto.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientDto.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.dto;
+package de.ids_mannheim.korap.oauth2.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientInfoDto.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientInfoDto.java
new file mode 100644
index 0000000..85003ae
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dto/OAuth2ClientInfoDto.java
@@ -0,0 +1,89 @@
+package de.ids_mannheim.korap.oauth2.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+
+@JsonInclude(Include.NON_EMPTY)
+public class OAuth2ClientInfoDto {
+
+ private String id;
+ private String name;
+ private String description;
+ private String isSuper;
+ private String redirectURI;
+ private String registeredBy;
+ private OAuth2ClientType type;
+
+ public OAuth2ClientInfoDto (OAuth2Client client) {
+ this.id = client.getId();
+ this.name = client.getName();
+ this.description = client.getDescription();
+ this.setType(client.getType());
+ this.redirectURI = client.getRedirectURI();
+ this.registeredBy = client.getRegisteredBy();
+
+ if (client.isSuper()) {
+ this.isSuper = "true";
+ }
+ }
+
+ public String getId () {
+ return id;
+ }
+
+ public void setId (String id) {
+ this.id = id;
+ }
+
+ public String getName () {
+ return name;
+ }
+
+ public void setName (String name) {
+ this.name = name;
+ }
+
+ public String getDescription () {
+ return description;
+ }
+
+ public void setDescription (String description) {
+ this.description = description;
+ }
+
+ public String getIsSuper () {
+ return isSuper;
+ }
+
+ public void setIsSuper (String isSuper) {
+ this.isSuper = isSuper;
+ }
+
+ public String getRedirectURI () {
+ return redirectURI;
+ }
+
+ public void setRedirectURI (String redirectURI) {
+ this.redirectURI = redirectURI;
+ }
+
+ public String getRegisteredBy () {
+ return registeredBy;
+ }
+
+ public void setRegisteredBy (String registeredBy) {
+ this.registeredBy = registeredBy;
+ }
+
+ public OAuth2ClientType getType () {
+ return type;
+ }
+
+ public void setType (OAuth2ClientType type) {
+ this.type = type;
+ }
+
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
index f7951d9..b26a90a 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/AccessScope.java
@@ -4,11 +4,14 @@
import java.util.List;
import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
import lombok.Getter;
import lombok.Setter;
@@ -21,11 +24,12 @@
private static final long serialVersionUID = -7356877266702636705L;
@Id
- private String id;
+ @Enumerated(EnumType.STRING)
+ private OAuth2Scope id;
public AccessScope () {}
- public AccessScope (String scope) {
+ public AccessScope (OAuth2Scope scope) {
this.id = scope;
}
@@ -37,7 +41,7 @@
@Override
public String toString () {
- return id;
+ return id.toString();
}
@Override
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 0fb0688..09c6e35 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
@@ -12,15 +12,11 @@
import javax.persistence.Table;
import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
-import lombok.Getter;
-import lombok.Setter;
/**
* @author margaretha
*
*/
-@Getter
-@Setter
@Entity
@Table(name = "oauth2_client")
public class OAuth2Client {
@@ -32,23 +28,95 @@
private String secret;
@Enumerated(EnumType.STRING)
private OAuth2ClientType type;
- @Column(name = "native")
- private boolean isNative;
+ @Column(name = "super")
+ private boolean isSuper;
@Column(name = "redirect_uri")
private String redirectURI;
@Column(name = "registered_by")
private String registeredBy;
private String description;
- @OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
+ @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "url_id")
private OAuth2ClientUrl clientUrl;
@Override
public String toString () {
return "id=" + id + ", name=" + name + ", secret=" + secret + ", type="
- + type + ", isNative=" + isNative + ", redirectURI="
+ + type + ", isSuper=" + isSuper() + ", redirectURI="
+ redirectURI + ", registeredBy=" + registeredBy
+ ", description=" + description;
}
+
+ public boolean isSuper () {
+ return isSuper;
+ }
+
+ public void setSuper (boolean isSuper) {
+ this.isSuper = isSuper;
+ }
+
+ public String getId () {
+ return id;
+ }
+
+ public void setId (String id) {
+ this.id = id;
+ }
+
+ public String getName () {
+ return name;
+ }
+
+ public void setName (String name) {
+ this.name = name;
+ }
+
+ public String getSecret () {
+ return secret;
+ }
+
+ public void setSecret (String secret) {
+ this.secret = secret;
+ }
+
+ public OAuth2ClientType getType () {
+ return type;
+ }
+
+ public void setType (OAuth2ClientType type) {
+ this.type = type;
+ }
+
+ public String getRedirectURI () {
+ return redirectURI;
+ }
+
+ public void setRedirectURI (String redirectURI) {
+ this.redirectURI = redirectURI;
+ }
+
+ public String getRegisteredBy () {
+ return registeredBy;
+ }
+
+ public void setRegisteredBy (String registeredBy) {
+ this.registeredBy = registeredBy;
+ }
+
+ public String getDescription () {
+ return description;
+ }
+
+ public void setDescription (String description) {
+ this.description = description;
+ }
+
+ public OAuth2ClientUrl getClientUrl () {
+ return clientUrl;
+ }
+
+ public void setClientUrl (OAuth2ClientUrl clientUrl) {
+ this.clientUrl = clientUrl;
+ }
}
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 7ce105f..cbd638d 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,9 +1,7 @@
package de.ids_mannheim.korap.oauth2.oltu.service;
-import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
-import java.net.URLEncoder;
import java.time.ZonedDateTime;
import javax.servlet.http.HttpServletRequest;
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 bb9baa5..16ff581 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
@@ -2,6 +2,7 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -211,14 +212,16 @@
OAuth2Client client =
clientService.authenticateClient(clientId, clientSecret);
- if (!client.isNative()) {
+ if (!client.isSuper()) {
throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
"Password grant is not allowed for third party clients",
OAuth2Error.UNAUTHORIZED_CLIENT);
}
if (scopes == null || scopes.isEmpty()) {
- scopes = config.getDefaultAccessScopes();
+ scopes = new HashSet<String>(1);
+ scopes.add("all");
+// scopes = config.getDefaultAccessScopes();
}
ZonedDateTime authenticationTime =
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
index 341ff97..5997ca0 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdAuthorizationService.java
@@ -111,9 +111,6 @@
if (scope != null) {
scopeSet = new HashSet<>(scope.toStringList());
}
- else {
- scopeSet = config.getDefaultAccessScopes();
- }
createAuthorization(username, clientId, redirectUriStr, scopeSet,
code.getValue(), authenticationTime, nonce);
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
index 91e724a..a17b4c8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/openid/service/OpenIdTokenService.java
@@ -165,7 +165,7 @@
clientCredentials[1]);
}
- if (!client.isNative()) {
+ if (!client.isSuper()) {
throw new KustvaktException(StatusCodes.CLIENT_AUTHORIZATION_FAILED,
"Password grant is not allowed for third party clients",
OAuth2Error.UNAUTHORIZED_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 53027f4..cdd6a66 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
@@ -13,7 +13,6 @@
import de.ids_mannheim.korap.config.FullConfiguration;
import de.ids_mannheim.korap.dao.AdminDao;
-import de.ids_mannheim.korap.dto.OAuth2ClientDto;
import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -22,6 +21,8 @@
import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
import de.ids_mannheim.korap.oauth2.dao.OAuth2ClientDao;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientInfoDto;
import de.ids_mannheim.korap.oauth2.entity.AccessToken;
import de.ids_mannheim.korap.oauth2.entity.Authorization;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
@@ -86,7 +87,7 @@
redirectURI + " is invalid.", OAuth2Error.INVALID_REQUEST);
}
- boolean isNative = isNativeClient(url, redirectURI);
+ // boolean isNative = isNativeClient(url, redirectURI);
String secret = null;
String secretHashcode = null;
@@ -111,8 +112,8 @@
String id = codeGenerator.createRandomCode();
try {
clientDao.registerClient(id, secretHashcode, clientJson.getName(),
- clientJson.getType(), isNative, url, urlHashCode,
- redirectURI, registeredBy, clientJson.getDescription());
+ clientJson.getType(), url, urlHashCode, redirectURI,
+ registeredBy, clientJson.getDescription());
}
catch (Exception e) {
Throwable cause = e;
@@ -131,7 +132,7 @@
return new OAuth2ClientDto(id, secret);
}
-
+ @Deprecated
private boolean isNativeClient (String url, String redirectURI)
throws KustvaktException {
if (url == null || url.isEmpty() || redirectURI == null
@@ -170,7 +171,6 @@
return true;
}
-
public void deregisterClient (String clientId, String clientSecret,
String username) throws KustvaktException {
@@ -185,13 +185,13 @@
clientDao.deregisterClient(client);
// revoke all related authorization tokens
- List<Authorization> authList = authorizationDao
- .retrieveAuthorizationsByClientId(clientId);
- for (Authorization authorization : authList){
+ 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);
@@ -212,8 +212,7 @@
OAuth2Client client = authenticateClient(clientId, clientSecret);
if (!client.getType().equals(OAuth2ClientType.CONFIDENTIAL)) {
- throw new KustvaktException(
- StatusCodes.NOT_ALLOWED,
+ throw new KustvaktException(StatusCodes.NOT_ALLOWED,
"Operation is not allowed for public clients",
OAuth2Error.INVALID_REQUEST);
}
@@ -259,6 +258,14 @@
OAuth2Error.INVALID_REQUEST);
}
}
+ 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",
+ OAuth2Error.INVALID_CLIENT);
+ }
+ }
else if (!encryption.checkHash(clientSecret, client.getSecret(),
config.getPasscodeSaltField())) {
throw new KustvaktException(
@@ -267,7 +274,6 @@
}
}
-
public OAuth2Client authenticateClientId (String clientId)
throws KustvaktException {
if (clientId == null || clientId.isEmpty()) {
@@ -279,4 +285,36 @@
return clientDao.retrieveClientById(clientId);
}
+
+ public void updatePrivilege (String username, String clientId,
+ boolean isSuper) throws KustvaktException {
+
+ 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.");
+ }
+ client.setSuper(isSuper);
+ clientDao.updateClient(client);
+ }
+ else {
+ throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+ "Unauthorized operation for user: " + username, username);
+ }
+ }
+
+ public OAuth2ClientInfoDto retrieveClientInfo (String username,
+ String clientId) throws KustvaktException {
+ OAuth2Client client = clientDao.retrieveClientById(clientId);
+ if (adminDao.isAdmin(username)
+ || username.equals(client.getRegisteredBy())) {
+ return new OAuth2ClientInfoDto(client);
+ }
+ else {
+ throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+ "Unauthorized operation for user: " + username, username);
+ }
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
index c820a30..bfc35c1 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ScopeService.java
@@ -45,8 +45,18 @@
Set<AccessScope> requestedScopes =
new HashSet<AccessScope>(scopes.size());
int index;
+ OAuth2Scope oauth2Scope = null;
for (String scope : scopes) {
- index = definedScopes.indexOf(new AccessScope(scope));
+ try{
+ oauth2Scope = Enum.valueOf(OAuth2Scope.class, scope.toUpperCase());
+ }
+ catch (IllegalArgumentException e) {
+ throw new KustvaktException(StatusCodes.INVALID_SCOPE,
+ scope + " is an invalid scope",
+ OAuth2Error.INVALID_SCOPE);
+ }
+
+ index = definedScopes.indexOf(new AccessScope(oauth2Scope));
if (index == -1) {
throw new KustvaktException(StatusCodes.INVALID_SCOPE,
scope + " is an invalid scope",
@@ -88,15 +98,16 @@
return filteredScopes;
}
- public void verifyScope (TokenContext context, OAuth2Scope requestScope)
+ public void verifyScope (TokenContext context, OAuth2Scope requiredScope)
throws KustvaktException {
if (!adminDao.isAdmin(context.getUsername())
&& context.getTokenType().equals(TokenType.BEARER)) {
Map<String, Object> parameters = context.getParameters();
- String scope = (String) parameters.get(Attributes.SCOPE);
- if (!scope.contains(requestScope.toString())) {
+ String authorizedScope = (String) parameters.get(Attributes.SCOPE);
+ if (!authorizedScope.contains(OAuth2Scope.ALL.toString())
+ && !authorizedScope.contains(requiredScope.toString())) {
throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
- "Scope " + requestScope + " is not authorized");
+ "Scope " + requiredScope + " is not authorized");
}
}
}
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 082f976..ac082a9 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
@@ -27,10 +27,12 @@
import com.sun.jersey.spi.container.ResourceFilters;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
import de.ids_mannheim.korap.oauth2.oltu.OAuth2AuthorizationRequest;
import de.ids_mannheim.korap.oauth2.oltu.OAuth2RevokeTokenRequest;
import de.ids_mannheim.korap.oauth2.oltu.service.OltuAuthorizationService;
import de.ids_mannheim.korap.oauth2.oltu.service.OltuTokenService;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
@@ -47,6 +49,8 @@
private OltuTokenService tokenService;
@Autowired
private OltuAuthorizationService authorizationService;
+ @Autowired
+ private OAuth2ScopeService scopeService;
/**
* Requests an authorization code.
@@ -73,7 +77,6 @@
@Path("authorize")
@ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response requestAuthorizationCode (
@Context HttpServletRequest request,
@Context SecurityContext context, @FormParam("state") String state,
@@ -82,10 +85,12 @@
TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
String username = tokenContext.getUsername();
ZonedDateTime authTime = tokenContext.getAuthenticationTime();
-
- HttpServletRequest requestWithForm =
- new FormRequestWrapper(request, form);
+
try {
+ scopeService.verifyScope(tokenContext, OAuth2Scope.AUTHORIZE);
+
+ HttpServletRequest requestWithForm =
+ new FormRequestWrapper(request, form);
OAuth2AuthorizationRequest authzRequest =
new OAuth2AuthorizationRequest(requestWithForm);
String uri = authorizationService.requestAuthorizationCode(
@@ -218,7 +223,6 @@
@POST
@Path("revoke")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response revokeAccessToken (@Context HttpServletRequest request,
MultivaluedMap<String, String> form) {
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 43e940b..e9aa803 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
@@ -32,12 +32,14 @@
import com.sun.jersey.spi.container.ResourceFilters;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
import de.ids_mannheim.korap.oauth2.openid.OpenIdConfiguration;
import de.ids_mannheim.korap.oauth2.openid.OpenIdHttpRequestWrapper;
import de.ids_mannheim.korap.oauth2.openid.service.JWKService;
import de.ids_mannheim.korap.oauth2.openid.service.OpenIdAuthorizationService;
import de.ids_mannheim.korap.oauth2.openid.service.OpenIdConfigService;
import de.ids_mannheim.korap.oauth2.openid.service.OpenIdTokenService;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OpenIdResponseHandler;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
@@ -56,7 +58,9 @@
private JWKService jwkService;
@Autowired
private OpenIdConfigService configService;
-
+ @Autowired
+ private OAuth2ScopeService scopeService;
+
@Autowired
private OpenIdResponseHandler openIdResponseHandler;
@@ -135,6 +139,8 @@
URI uri = null;
try {
+ scopeService.verifyScope(tokenContext, OAuth2Scope.AUTHORIZE);
+
if (isAuthentication) {
authzService.checkRedirectUriParam(map);
}
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 293685e..387194c 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
@@ -3,6 +3,7 @@
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@@ -17,31 +18,50 @@
import com.sun.jersey.spi.container.ResourceFilters;
-import de.ids_mannheim.korap.dto.OAuth2ClientDto;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientInfoDto;
import de.ids_mannheim.korap.oauth2.service.OAuth2ClientService;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
import de.ids_mannheim.korap.web.filter.BlockingFilter;
import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
-
/**
* Defines controllers for OAuth2 clients, namely applications
* performing actions such as searching and retrieving match
* information on behalf of users.
*
+ * <br /><br />
+ * According to its privileges, clients are categorized into super and
+ * normal clients. Super clients are intended only for clients that
+ * are part of KorAP. They has special privileges to use controllers
+ * that usually are not allowed for normal clients, for instance using
+ * OAuth2 password grant to obtain access tokens.
+ *
+ * <br /><br />
+ * By default, clients are set as normal clients. Super clients has to
+ * be set manually by an admin, e.g by using
+ * {@link #updateClientPrivilege(SecurityContext, String, boolean)}
+ * controller. Only confidential clients are allowed to be super
+ * clients.
+ *
* @author margaretha
*
*/
@Controller
@Path("oauth2/client")
+@ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
public class OAuthClientController {
@Autowired
private OAuth2ClientService clientService;
@Autowired
+ private OAuth2ScopeService scopeService;
+ @Autowired
private OAuth2ResponseHandler responseHandler;
/**
@@ -70,13 +90,13 @@
@Path("register")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
- @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
public OAuth2ClientDto registerClient (
@Context SecurityContext securityContext,
OAuth2ClientJson clientJson) {
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.REGISTER_CLIENT);
return clientService.registerClient(clientJson,
context.getUsername());
}
@@ -85,7 +105,6 @@
}
}
-
/**
* Deregisters a client requires client owner authentication. For
* confidential clients, client authentication is also required.
@@ -101,7 +120,6 @@
@DELETE
@Path("deregister/{client_id}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
public Response deregisterPublicClient (
@Context SecurityContext securityContext,
@PathParam("client_id") String clientId,
@@ -109,6 +127,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DEREGISTER_CLIENT);
clientService.deregisterClient(clientId, clientSecret,
context.getUsername());
return Response.ok().build();
@@ -132,7 +151,6 @@
@Path("reset")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
- @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
public OAuth2ClientDto resetClientSecret (
@Context SecurityContext securityContext,
@FormParam("client_id") String clientId,
@@ -140,6 +158,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.RESET_CLIENT_SECRET);
return clientService.resetSecret(clientId, clientSecret,
context.getUsername());
}
@@ -148,4 +167,51 @@
}
}
+ /**
+ * Facilitates editing client privileges for admin purposes, e.g.
+ * setting a specific client to be a super client, and vice versa.
+ * Only confidential clients are allowed to be super clients.
+ *
+ * @param securityContext
+ * @param clientId
+ * @param super true indicating super client, false otherwise
+ * @return Response status OK, if successful
+ */
+ @POST
+ @Path("privilege")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response updateClientPrivilege (
+ @Context SecurityContext securityContext,
+ @FormParam("client_id") String clientId,
+ @FormParam("super") String isSuper) {
+ TokenContext context =
+ (TokenContext) securityContext.getUserPrincipal();
+ try {
+ scopeService.verifyScope(context, OAuth2Scope.ADMIN);
+ clientService.updatePrivilege(context.getUsername(), clientId,
+ Boolean.valueOf(isSuper));
+ return Response.ok().build();
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+
+ @GET
+ @Path("info/{client_id}")
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public OAuth2ClientInfoDto retrieveClientInfo (
+ @Context SecurityContext securityContext,
+ @PathParam("client_id") String clientId) {
+ TokenContext context =
+ (TokenContext) securityContext.getUserPrincipal();
+ try {
+ scopeService.verifyScope(context, OAuth2Scope.CLIENT_INFO);
+ return clientService.retrieveClientInfo(context.getUsername(),
+ clientId);
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
index a0850ce..8e82de0 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
@@ -24,6 +24,8 @@
import de.ids_mannheim.korap.constant.UserGroupStatus;
import de.ids_mannheim.korap.dto.UserGroupDto;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
import de.ids_mannheim.korap.service.UserGroupService;
import de.ids_mannheim.korap.web.KustvaktResponseHandler;
@@ -54,6 +56,8 @@
private KustvaktResponseHandler kustvaktResponseHandler;
@Autowired
private UserGroupService service;
+ @Autowired
+ private OAuth2ScopeService scopeService;
/**
* Returns all user-groups in which a user is an active or a
@@ -74,6 +78,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.USER_GROUP_INFO);
return service.retrieveUserGroup(context.getUsername());
}
catch (KustvaktException e) {
@@ -106,6 +111,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.ADMIN);
return service.retrieveUserGroupByStatus(username,
context.getUsername(), status);
}
@@ -131,6 +137,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.ADMIN);
return service.searchById(context.getUsername(), groupId);
}
catch (KustvaktException e) {
@@ -168,6 +175,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.CREATE_USER_GROUP);
service.createUserGroup(group, context.getUsername());
return Response.ok().build();
}
@@ -178,8 +186,7 @@
/**
* Deletes a user-group specified by the group id. Only group
- * owner
- * and system admins can delete groups.
+ * owner and system admins can delete groups.
*
* @param securityContext
* @param groupId
@@ -192,6 +199,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_USER_GROUP);
service.deleteGroup(groupId, context.getUsername());
return Response.ok().build();
}
@@ -219,6 +227,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_USER_GROUP_MEMBER);
service.deleteGroupMember(memberId, groupId, context.getUsername());
return Response.ok().build();
}
@@ -247,6 +256,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.ADD_USER_GROUP_MEMBER);
service.inviteGroupMembers(group, context.getUsername());
return Response.ok().build();
}
@@ -279,6 +289,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.ADD_USER_GROUP_MEMBER_ROLE);
service.addMemberRoles(context.getUsername(), groupId,
memberUsername, roleIds);
return Response.ok().build();
@@ -290,8 +301,7 @@
/**
* Deletes roles of a member of a user-group. Only user-group
- * admins
- * and system admins are allowed.
+ * admins and system admins are allowed.
*
* @param securityContext
* @param groupId
@@ -312,6 +322,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_USER_GROUP_MEMBER_ROLE);
service.deleteMemberRoles(context.getUsername(), groupId,
memberUsername, roleIds);
return Response.ok().build();
@@ -339,6 +350,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.ADD_USER_GROUP_MEMBER);
service.acceptInvitation(groupId, context.getUsername());
return Response.ok().build();
}
@@ -367,6 +379,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_USER_GROUP_MEMBER);
service.deleteGroupMember(context.getUsername(), groupId,
context.getUsername());
return Response.ok().build();
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
index 24d6e52..2627bdc 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
@@ -21,13 +21,11 @@
import com.sun.jersey.spi.container.ResourceFilters;
-import de.ids_mannheim.korap.constant.TokenType;
import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
import de.ids_mannheim.korap.constant.VirtualCorpusType;
import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
import de.ids_mannheim.korap.dto.VirtualCorpusDto;
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.oauth2.service.OAuth2ScopeService;
import de.ids_mannheim.korap.security.context.TokenContext;
@@ -229,11 +227,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
- if (context.getTokenType().equals(TokenType.BEARER)){
- throw new KustvaktException(
- StatusCodes.AUTHENTICATION_FAILED,
- "Token type Bearer is not allowed");
- }
+ scopeService.verifyScope(context, OAuth2Scope.ADMIN);
return service.listVCByType(context.getUsername(), createdBy, type);
}
catch (KustvaktException e) {
@@ -258,6 +252,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_VC);
service.deleteVC(context.getUsername(), vcId);
}
catch (KustvaktException e) {
@@ -289,6 +284,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.SHARE_VC);
service.shareVC(context.getUsername(), vcId, groupId);
}
catch (KustvaktException e) {
@@ -315,6 +311,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.DELETE_VC_ACCESS);
service.deleteVCAccess(accessId, context.getUsername());
}
catch (KustvaktException e) {
@@ -348,6 +345,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.VC_ACCESS_INFO);
return service.listVCAccessByVC(context.getUsername(), vcId);
}
catch (KustvaktException e) {
@@ -377,6 +375,7 @@
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
+ scopeService.verifyScope(context, OAuth2Scope.VC_ACCESS_INFO);
return service.listVCAccessByGroup(context.getUsername(), groupId);
}
catch (KustvaktException e) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
index d0a6cf6..57d232d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/AuthenticationFilter.java
@@ -75,15 +75,6 @@
context = authenticationManager.getTokenContext(
TokenType.BEARER, authData.getToken(), host,
ua);
- if (request.getPath().startsWith("oauth2")
- || request.getPath().startsWith("vc/access")
- || request.getPath().startsWith("vc/delete")
- || request.getPath().startsWith("group")
- || request.getPath().startsWith("user")) {
- throw new KustvaktException(
- StatusCodes.AUTHORIZATION_FAILED,
- "Token type Bearer is not allowed");
- }
break;
// EM: JWT token-based authentication scheme
case API:
diff --git a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
index dd55405..68bbfa7 100644
--- a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
+++ b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
@@ -4,48 +4,48 @@
VALUES("http://korap.ids-mannheim.de/confidential", 2087150261);
-- plain secret value is "secret"
-INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
+INSERT INTO oauth2_client(id,name,secret,type,super,url_id,
redirect_uri,registered_by, description)
VALUES ("fCBbQkAyYzI4NzUxMg","test confidential client",
"$2a$08$vi1FbuN3p6GcI1tSxMAoeuIYL8Yw3j6A8wJthaN8ZboVnrQaTwLPq",
"CONFIDENTIAL", 1, 2087150261,
"https://korap.ids-mannheim.de/confidential/redirect", "system",
- "This is a test native confidential client.");
+ "This is a test super confidential client.");
INSERT INTO oauth2_client_url(url,url_hashcode)
VALUES("http://third.party.com/confidential", 1712550103);
-- plain secret value is "secret"
-INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
+INSERT INTO oauth2_client(id,name,secret,type,super,url_id,
redirect_uri,registered_by, description)
-VALUES ("9aHsGW6QflV13ixNpez","test non native confidential client",
+VALUES ("9aHsGW6QflV13ixNpez","test non super confidential client",
"$2a$08$vi1FbuN3p6GcI1tSxMAoeuIYL8Yw3j6A8wJthaN8ZboVnrQaTwLPq",
"CONFIDENTIAL", 0, 1712550103,
"https://third.party.com/confidential/redirect", "system",
- "This is a test nonnative confidential client.");
+ "This is a test nonsuper confidential client.");
INSERT INTO oauth2_client_url(url,url_hashcode)
VALUES("http://third.party.client.com", -2137275617);
-INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
+INSERT INTO oauth2_client(id,name,secret,type,super,url_id,
redirect_uri, registered_by, description)
VALUES ("8bIDtZnH6NvRkW2Fq","third party client",null,
"PUBLIC", 0, -2137275617,
"https://third.party.client.com/redirect","system",
- "This is a test nonnative public client.");
+ "This is a test nonsuper public client.");
INSERT INTO oauth2_client_url(url,url_hashcode)
VALUES("http://korap.ids-mannheim.de/public", 1360724310);
-INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
- redirect_uri, registered_by, description)
-VALUES ("iBr3LsTCxOj7D2o0A5m","test public client",null,
- "PUBLIC", 1, 1360724310,
- "https://korap.ids-mannheim.de/public/redirect","system",
- "This is a test native public client.");
+--INSERT INTO oauth2_client(id,name,secret,type,super,url_id,
+-- redirect_uri, registered_by, description)
+--VALUES ("iBr3LsTCxOj7D2o0A5m","test public client",null,
+-- "PUBLIC", 1, 1360724310,
+-- "https://korap.ids-mannheim.de/public/redirect","system",
+-- "This is a test super public client.");
INSERT INTO oauth2_access_token(token,user_id,created_date, user_auth_time)
VALUES("fia0123ikBWn931470H8s5gRqx7Moc4p","marlin","2018-05-30 16:25:50",
diff --git a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
index dff4df8..47f0a0f 100644
--- a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
@@ -11,7 +11,7 @@
name VARCHAR(255) NOT NULL,
secret VARCHAR(255) DEFAULT NULL,
type VARCHAR(255) NOT NULL,
- native BOOLEAN DEFAULT FALSE,
+ super BOOLEAN DEFAULT FALSE,
redirect_uri TEXT DEFAULT NULL,
description VARCHAR(255) NOT NULL,
registered_by VARCHAR(100) NOT NULL,
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 98f3434..78d91aa 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
@@ -2,22 +2,27 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+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;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.core.util.MultivaluedMapImpl;
-import de.ids_mannheim.korap.authentication.http.TransferEncoding;
+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;
@@ -27,15 +32,48 @@
public class OAuth2AccessTokenTest extends SpringJerseyTest {
- private String clientId = "fCBbQkAyYzI4NzUxMg";
+ // normal client
+ private String clientId = "9aHsGW6QflV13ixNpez";
+ private String superClientId = "fCBbQkAyYzI4NzUxMg";
+ private String clientSecret = "secret";
- private JsonNode requestToken () throws KustvaktException {
+ private String requestAuthorizationCode (String scope, String authHeader)
+ throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
- form.add("grant_type", "password");
+ form.add("response_type", "code");
form.add("client_id", clientId);
- form.add("client_secret", "secret");
- form.add("username", "dory");
- form.add("password", "password");
+ 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
+ .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,
@@ -43,45 +81,85 @@
.entity(form).post(ClientResponse.class);
String entity = response.getEntity(String.class);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
JsonNode node = JsonUtils.readTree(entity);
return node;
}
- @Test
- public void testListVCScope () throws KustvaktException {
+ // client credentials in authorization header
+ private JsonNode requestTokenWithAuthorizationHeader (String code)
+ 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");
- form.add("scope", OAuth2Scope.VC_INFO.toString());
+ form.add("grant_type", "authorization_code");
+ form.add("client_id", clientId);
+ form.add("code", code);
ClientResponse response = resource().path("oauth2").path("token")
- .header(HttpHeaders.AUTHORIZATION,
- "Bearer" + TransferEncoding
- .encodeBase64("fCBbQkAyYzI4NzUxMg", "secret"))
+ .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);
- JsonNode node = JsonUtils.readTree(entity);
- String token = node.at("/access_token").asText();
+ return JsonUtils.readTree(entity);
+ }
- response = resource().path("vc").path("list")
+ @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);
+
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ assertEquals("all", node.at("/scope").asText());
+ String accessToken = node.at("/access_token").asText();
+
+ // test list user group
+ response = resource().path("group").path("list")
+ .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+ .get(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ node = JsonUtils.readTree(response.getEntity(String.class));
+ assertEquals(2, node.size());
+ }
+
+ @Test
+ public void testCustomAuthorizationScope () throws KustvaktException {
+ String authHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue("dory", "password");
+ String code = requestAuthorizationCode(OAuth2Scope.VC_INFO.toString(),
+ authHeader);
+ JsonNode node = requestTokenWithAuthorizationHeader(code);
+
+ String token = node.at("/access_token").asText();
+ assertTrue(node.at("/scope").asText()
+ .contains(OAuth2Scope.VC_INFO.toString()));
+
+ ClientResponse response = resource().path("vc").path("list")
.header(Attributes.AUTHORIZATION, "Bearer " + token)
.get(ClientResponse.class);
assertEquals(Status.OK.getStatusCode(), response.getStatus());
- entity = response.getEntity(String.class);
- node = JsonUtils.readTree(entity);
+ node = JsonUtils.readTree(response.getEntity(String.class));
assertEquals(4, node.size());
}
@Test
- public void testTokenAccessScope () throws KustvaktException, IOException {
- String accessToken = requestToken().at("/access_token").asText();
+ public void testDefaultScope () throws KustvaktException, IOException {
+ String accessToken = requestTokenWithAuthorizationCodeGrant()
+ .at("/access_token").asText();
testListVCScopeNotAuthorized(accessToken);
testListVCAccessBearerNotAuthorize(accessToken);
testSearchWithOAuth2Token(accessToken);
@@ -116,7 +194,7 @@
JsonNode node = JsonUtils.readTree(entity);
assertEquals(StatusCodes.AUTHORIZATION_FAILED,
node.at("/errors/0/0").asInt());
- assertEquals("Token type Bearer is not allowed",
+ assertEquals("Scope vc_access_info is not authorized",
node.at("/errors/0/1").asText());
}
@@ -161,10 +239,11 @@
@Test
public void testRevokeAccessTokenConfidentialClient ()
throws KustvaktException {
- String accessToken = requestToken().at("/access_token").asText();
+ String accessToken = requestTokenWithAuthorizationCodeGrant()
+ .at("/access_token").asText();
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("token", accessToken);
- form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+ form.add("client_id", clientId);
form.add("client_secret", "secret");
ClientResponse response = resource().path("oauth2").path("revoke")
@@ -200,10 +279,10 @@
@Test
public void testRevocationAfterRequestRefreshToken ()
throws KustvaktException {
- JsonNode node = requestToken();
+ JsonNode node = requestTokenWithAuthorizationCodeGrant();
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);
@@ -221,8 +300,65 @@
node = JsonUtils.readTree(entity);
assertNotNull(node.at("/access_token").asText());
- assertEquals(refreshToken,node.at("/refresh_token").asText());
-
+ assertEquals(refreshToken, node.at("/refresh_token").asText());
+
testSearchWithRevokedToken(accessToken);
}
+
+ @Test
+ public void testRequestAuthorizationWithBearerTokenUnauthorized () throws KustvaktException {
+ String userAuthToken = requestTokenWithAuthorizationCodeGrant()
+ .at("/access_token").asText();
+
+ 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, "Bearer " + userAuthToken)
+ .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ assertEquals(StatusCodes.AUTHORIZATION_FAILED,
+ node.at("/errors/0/0").asInt());
+ assertEquals("Scope authorize is not authorized",
+ node.at("/errors/0/1").asText());
+ }
+
+ @Test
+ public void testRequestAuthorizationWithBearerToken ()
+ throws KustvaktException {
+ String userAuthToken = requestTokenWithPasswordGrant();
+ String code = requestAuthorizationCode(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 ffecbb3..9c3d536 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
@@ -94,7 +94,6 @@
testDeregisterConfidentialClient(clientId, newclientSecret);
}
-
private void testRegisterClientNonUniqueURL () throws KustvaktException {
ClientResponse response = registerConfidentialClient();
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -127,9 +126,8 @@
assertNotNull(clientId);
assertTrue(node.at("/client_secret").isMissingNode());
- testDeregisterPublicClientMissingUserAuthentication(clientId);
- testDeregisterPublicClientMissingId();
- testDeregisterPublicClient(clientId);
+ testResetPublicClientSecret(clientId);
+ testAccessTokenAfterDeregistration(clientId);
}
@Test
@@ -155,35 +153,9 @@
assertNotNull(clientId);
assertTrue(node.at("/client_secret").isMissingNode());
- testResetPublicClientSecret(clientId);
- }
-
- @Test
- public void testRegisterNativeClient () throws UniformInterfaceException,
- ClientHandlerException, KustvaktException {
- OAuth2ClientJson json = new OAuth2ClientJson();
- json.setName("NativeClient");
- json.setType(OAuth2ClientType.PUBLIC);
- json.setUrl("http://korap.ids-mannheim.de/native");
- json.setRedirectURI("https://korap.ids-mannheim.de/native/redirect");
- json.setDescription("This is a native test client.");
-
- ClientResponse response = resource().path("oauth2").path("client")
- .path("register")
- .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
- .createBasicAuthorizationHeaderValue(username, "pass"))
- .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
- .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
- .entity(json).post(ClientResponse.class);
-
- String entity = response.getEntity(String.class);
- assertEquals(Status.OK.getStatusCode(), response.getStatus());
- JsonNode node = JsonUtils.readTree(entity);
- String clientId = node.at("/client_id").asText();
-
- // EM: need to check native
-
- testAccessTokenAfterDeregistration(clientId);
+ testDeregisterPublicClientMissingUserAuthentication(clientId);
+ testDeregisterPublicClientMissingId();
+ testDeregisterPublicClient(clientId);
}
private void testAccessTokenAfterDeregistration (String clientId)
@@ -420,4 +392,55 @@
return newClientSecret;
}
+
+ @Test
+ public void testUpdateClientPrivilege () throws KustvaktException {
+ ClientResponse response = registerConfidentialClient();
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ String clientId = node.at("/client_id").asText();
+
+ MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+ form.add("client_id", clientId);
+ form.add("super", "true");
+
+ updateClientPrivilege(form);
+ 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"))
+ .get(ClientResponse.class);
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ String entity = response.getEntity(String.class);
+ return JsonUtils.readTree(entity);
+ }
}
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 3dabb7b..5d452e8 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
@@ -181,6 +181,46 @@
}
@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);
+
+ 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);
+ 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);
+ testRequestRefreshTokenInvalidClient(refreshToken);
+ testRequestRefreshTokenInvalidRefreshToken(clientId);
+
+ testRevokeTokenPublicClient(refreshToken, clientId, "refresh_token");
+ testRequestRefreshWithRevokedRefreshToken(clientId, refreshToken);
+ }
+
+ @Test
public void testRequestTokenAuthorizationConfidential ()
throws KustvaktException {
@@ -203,7 +243,6 @@
tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
tokenForm.add("client_secret", "secret");
tokenForm.add("code", code);
- System.out.println(code);
response = requestToken(tokenForm);
String entity = response.getEntity(String.class);
@@ -437,7 +476,7 @@
@Test
public void testRequestTokenPasswordGrantPublic ()
throws KustvaktException {
- String clientId = "iBr3LsTCxOj7D2o0A5m";
+ String clientId = "8bIDtZnH6NvRkW2Fq";
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", "password");
form.add("username", "dory");
@@ -447,35 +486,23 @@
ClientResponse response = requestToken(form);
String entity = response.getEntity(String.class);
- assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
JsonNode node = JsonUtils.readTree(entity);
- String accessToken = node.at("/access_token").asText();
- assertEquals(TokenType.BEARER.toString(),
- node.at("/token_type").asText());
- assertNotNull(node.at("/expires_in").asText());
-
-
- testRevokeTokenPublicClient(accessToken, clientId, "access_token");
-
- String refreshToken = node.at("/refresh_token").asText();
- testRequestRefreshTokenInvalidScope(clientId, refreshToken);
- testRequestRefreshTokenPublicClient(clientId, refreshToken);
- testRequestRefreshTokenInvalidClient(refreshToken);
- testRequestRefreshTokenInvalidRefreshToken(clientId);
-
- testRevokeTokenPublicClient(refreshToken, clientId, "refresh_token");
- testRequestRefreshWithRevokedRefreshToken(clientId, refreshToken);
+ 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 testRequestTokenPasswordGrantNonNative ()
+ 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 nonnative
+ // confidential non-super
form.add("client_id", "9aHsGW6QflV13ixNpez");
form.add("client_secret", "secret");
@@ -639,7 +666,7 @@
throws KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
- form.add("client_id", "8bIDtZnH6NvRkW2Fq");
+ form.add("client_id", "iBr3LsTCxOj7D2o0A5m");
form.add("refresh_token", refreshToken);
ClientResponse response = resource().path("oauth2").path("token")
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 eb716ab..abb44d7 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
@@ -103,8 +103,6 @@
assertEquals("thisIsMyState", params.getFirst("state"));
}
-
-
private void testRequestAuthorizationCodeWithoutOpenID (
MultivaluedMap<String, String> form, String redirectUri)
throws KustvaktException {
@@ -350,14 +348,13 @@
assertEquals(nonce, claimsSet.getClaim("nonce"));
}
-
// no openid
@Test
public void testRequestAccessTokenWithPassword ()
throws KustvaktException, ParseException, InvalidKeySpecException,
NoSuchAlgorithmException, JOSEException {
// public client
- String client_id = "iBr3LsTCxOj7D2o0A5m";
+ String client_id = "8bIDtZnH6NvRkW2Fq";
MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
testRequestAccessTokenMissingGrant(tokenForm);
@@ -373,13 +370,12 @@
ClientResponse tokenResponse = sendTokenRequest(tokenForm);
String entity = tokenResponse.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
- assertNotNull(node.at("/access_token").asText());
- assertNotNull(node.at("/refresh_token").asText());
- assertEquals(TokenType.BEARER.toString(),
- node.at("/token_type").asText());
- assertNotNull(node.at("/expires_in").asText());
- }
+ assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
+ node.at("/error").asText());
+ assertEquals("Password grant is not allowed for third party clients",
+ node.at("/error_description").asText());
+ }
private void testRequestAccessTokenMissingUsername (
MultivaluedMap<String, String> tokenForm) throws KustvaktException {