Details
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Config.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Config.java
index ae3edaa..4e628e5 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Config.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Config.java
@@ -17,6 +17,9 @@
package org.keycloak.admin.client;
+import static org.keycloak.OAuth2Constants.CLIENT_CREDENTIALS;
+import static org.keycloak.OAuth2Constants.PASSWORD;
+
/**
* @author rodrigo.sasaki@icarros.com.br
*/
@@ -28,14 +31,21 @@ public class Config {
private String password;
private String clientId;
private String clientSecret;
+ private String grantType;
public Config(String serverUrl, String realm, String username, String password, String clientId, String clientSecret) {
+ this(serverUrl, realm, username, password, clientId, clientSecret, PASSWORD);
+ }
+
+ public Config(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, String grantType) {
this.serverUrl = serverUrl;
this.realm = realm;
this.username = username;
this.password = password;
this.clientId = clientId;
this.clientSecret = clientSecret;
+ this.grantType = grantType;
+ checkGrantType(grantType);
}
public String getServerUrl() {
@@ -86,8 +96,23 @@ public class Config {
this.clientSecret = clientSecret;
}
- public boolean isPublicClient(){
+ public boolean isPublicClient() {
return clientSecret == null;
}
+ public String getGrantType() {
+ return grantType;
+ }
+
+ public void setGrantType(String grantType) {
+ this.grantType = grantType;
+ checkGrantType(grantType);
+ }
+
+ public static void checkGrantType(String grantType) {
+ if (!PASSWORD.equals(grantType) && !CLIENT_CREDENTIALS.equals(grantType)) {
+ throw new IllegalArgumentException("Unsupported grantType: " + grantType +
+ " (only " + PASSWORD + " and " + CLIENT_CREDENTIALS + " are supported)");
+ }
+ }
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 52c5561..5e30a66 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -28,25 +28,25 @@ import org.keycloak.admin.client.token.TokenManager;
import java.net.URI;
+import static org.keycloak.OAuth2Constants.PASSWORD;
+
/**
* Provides a Keycloak client. By default, this implementation uses a {@link ResteasyClient RESTEasy client} with the
* default {@link ResteasyClientBuilder} settings. To customize the underling client, use a {@link KeycloakBuilder} to
* create a Keycloak client.
*
- * @see KeycloakBuilder
- *
* @author rodrigo.sasaki@icarros.com.br
+ * @see KeycloakBuilder
*/
public class Keycloak {
-
private final Config config;
private final TokenManager tokenManager;
private final ResteasyWebTarget target;
private final ResteasyClient client;
- Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, ResteasyClient resteasyClient){
- config = new Config(serverUrl, realm, username, password, clientId, clientSecret);
- client = resteasyClient != null ? resteasyClient : new ResteasyClientBuilder().connectionPoolSize(10).build();
+ Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret, String grantType, ResteasyClient resteasyClient) {
+ config = new Config(serverUrl, realm, username, password, clientId, clientSecret, grantType);
+ client = resteasyClient != null ? resteasyClient : new ResteasyClientBuilder().build();
tokenManager = new TokenManager(config, client);
@@ -55,27 +55,27 @@ public class Keycloak {
target.register(new BearerAuthFilter(tokenManager));
}
- public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, String clientSecret){
- return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, null);
+ public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, String clientSecret) {
+ return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, PASSWORD, null);
}
- public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId){
- return new Keycloak(serverUrl, realm, username, password, clientId, null, null);
+ public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId) {
+ return new Keycloak(serverUrl, realm, username, password, clientId, null, PASSWORD, null);
}
- public RealmsResource realms(){
+ public RealmsResource realms() {
return target.proxy(RealmsResource.class);
}
- public RealmResource realm(String realmName){
+ public RealmResource realm(String realmName) {
return realms().realm(realmName);
}
- public ServerInfoResource serverInfo(){
+ public ServerInfoResource serverInfo() {
return target.proxy(ServerInfoResource.class);
}
- public TokenManager tokenManager(){
+ public TokenManager tokenManager() {
return tokenManager;
}
@@ -98,5 +98,4 @@ public class Keycloak {
public void close() {
client.close();
}
-
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/KeycloakBuilder.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/KeycloakBuilder.java
index 5a61ffb..e192d9a 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/KeycloakBuilder.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/KeycloakBuilder.java
@@ -20,15 +20,17 @@ package org.keycloak.admin.client;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import static org.keycloak.OAuth2Constants.CLIENT_CREDENTIALS;
+import static org.keycloak.OAuth2Constants.PASSWORD;
+
/**
* Provides a {@link Keycloak} client builder with the ability to customize the underlying
* {@link ResteasyClient RESTEasy client} used to communicate with the Keycloak server.
- *
+ * <p>
* <p>Example usage with a connection pool size of 20:</p>
- *
* <pre>
* Keycloak keycloak = KeycloakBuilder.builder()
- * .serverUrl("https:/sso.example.com/auth")
+ * .serverUrl("https://sso.example.com/auth")
* .realm("realm")
* .username("user")
* .password("pass")
@@ -37,6 +39,16 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
* .resteasyClient(new ResteasyClientBuilder().connectionPoolSize(20).build())
* .build();
* </pre>
+ * <p>Example usage with grant_type=client_credentials</p>
+ * <pre>
+ * Keycloak keycloak = KeycloakBuilder.builder()
+ * .serverUrl("https://sso.example.com/auth")
+ * .realm("example")
+ * .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
+ * .clientId("client")
+ * .clientSecret("secret")
+ * .build();
+ * </pre>
*
* @author Scott Rossillo
* @see ResteasyClientBuilder
@@ -48,6 +60,7 @@ public class KeycloakBuilder {
private String password;
private String clientId;
private String clientSecret;
+ private String grantType = PASSWORD;
private ResteasyClient resteasyClient;
public KeycloakBuilder serverUrl(String serverUrl) {
@@ -60,6 +73,12 @@ public class KeycloakBuilder {
return this;
}
+ public KeycloakBuilder grantType(String grantType) {
+ Config.checkGrantType(grantType);
+ this.grantType = grantType;
+ return this;
+ }
+
public KeycloakBuilder username(String username) {
this.username = username;
return this;
@@ -97,19 +116,25 @@ public class KeycloakBuilder {
throw new IllegalStateException("realm required");
}
- if (username == null) {
- throw new IllegalStateException("username required");
- }
-
- if (password == null) {
- throw new IllegalStateException("password required");
+ if (PASSWORD.equals(grantType)) {
+ if (username == null) {
+ throw new IllegalStateException("username required");
+ }
+
+ if (password == null) {
+ throw new IllegalStateException("password required");
+ }
+ } else if (CLIENT_CREDENTIALS.equals(grantType)) {
+ if (clientSecret == null) {
+ throw new IllegalStateException("clientSecret required with grant_type=client_credentials");
+ }
}
if (clientId == null) {
throw new IllegalStateException("clientId required");
}
- return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, resteasyClient);
+ return new Keycloak(serverUrl, realm, username, password, clientId, clientSecret, grantType, resteasyClient);
}
private KeycloakBuilder() {
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
index e325681..bb32dae 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/token/TokenManager.java
@@ -27,11 +27,12 @@ import org.keycloak.representations.AccessTokenResponse;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.core.Form;
+import static org.keycloak.OAuth2Constants.*;
+
/**
* @author rodrigo.sasaki@icarros.com.br
*/
public class TokenManager {
-
private static final long DEFAULT_MIN_VALIDITY = 30;
private AccessTokenResponse currentToken;
@@ -39,61 +40,67 @@ public class TokenManager {
private long minTokenValidity = DEFAULT_MIN_VALIDITY;
private final Config config;
private final TokenService tokenService;
+ private final String accessTokenGrantType;
- public TokenManager(Config config, ResteasyClient client){
+ public TokenManager(Config config, ResteasyClient client) {
this.config = config;
ResteasyWebTarget target = client.target(config.getServerUrl());
- if(!config.isPublicClient()){
+ if (!config.isPublicClient()) {
target.register(new BasicAuthFilter(config.getClientId(), config.getClientSecret()));
}
- tokenService = target.proxy(TokenService.class);
+ this.tokenService = target.proxy(TokenService.class);
+ this.accessTokenGrantType = config.getGrantType();
+
+ if (CLIENT_CREDENTIALS.equals(accessTokenGrantType) && config.isPublicClient()) {
+ throw new IllegalArgumentException("Can't use " + GRANT_TYPE + "=" + CLIENT_CREDENTIALS + " with public client");
+ }
}
- public String getAccessTokenString(){
+ public String getAccessTokenString() {
return getAccessToken().getToken();
}
- public synchronized AccessTokenResponse getAccessToken(){
- if(currentToken == null){
+ public synchronized AccessTokenResponse getAccessToken() {
+ if (currentToken == null) {
grantToken();
- }else if(tokenExpired()){
+ } else if (tokenExpired()) {
refreshToken();
}
return currentToken;
}
- public AccessTokenResponse grantToken(){
- Form form = new Form()
- .param("grant_type", "password")
- .param("username", config.getUsername())
+ public AccessTokenResponse grantToken() {
+ Form form = new Form().param(GRANT_TYPE, accessTokenGrantType);
+ if (PASSWORD.equals(accessTokenGrantType)) {
+ form.param("username", config.getUsername())
.param("password", config.getPassword());
+ }
- if(config.isPublicClient()){
- form.param("client_id", config.getClientId());
+ if (config.isPublicClient()) {
+ form.param(CLIENT_ID, config.getClientId());
}
int requestTime = Time.currentTime();
synchronized (this) {
- currentToken = tokenService.grantToken( config.getRealm(), form.asMap() );
+ currentToken = tokenService.grantToken(config.getRealm(), form.asMap());
expirationTime = requestTime + currentToken.getExpiresIn();
}
return currentToken;
}
- public AccessTokenResponse refreshToken(){
- Form form = new Form()
- .param("grant_type", "refresh_token")
- .param("refresh_token", currentToken.getRefreshToken());
+ public AccessTokenResponse refreshToken() {
+ Form form = new Form().param(GRANT_TYPE, REFRESH_TOKEN)
+ .param(REFRESH_TOKEN, currentToken.getRefreshToken());
- if(config.isPublicClient()){
- form.param("client_id", config.getClientId());
+ if (config.isPublicClient()) {
+ form.param(CLIENT_ID, config.getClientId());
}
try {
int requestTime = Time.currentTime();
synchronized (this) {
- currentToken = tokenService.refreshToken( config.getRealm(), form.asMap() );
+ currentToken = tokenService.refreshToken(config.getRealm(), form.asMap());
expirationTime = requestTime + currentToken.getExpiresIn();
}
return currentToken;