KEYCLOAK-231 Support for sending scope parameter from applications and oauth clients
This commit is contained in:
parent
e904ca8b58
commit
d309fab825
10 changed files with 77 additions and 11 deletions
|
@ -17,6 +17,7 @@ public class AbstractOAuthClient {
|
|||
protected KeyStore truststore;
|
||||
protected String authUrl;
|
||||
protected String codeUrl;
|
||||
protected String scope;
|
||||
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
|
||||
protected String stateCookiePath;
|
||||
protected boolean isSecure;
|
||||
|
@ -68,6 +69,14 @@ public class AbstractOAuthClient {
|
|||
this.codeUrl = codeUrl;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
public String getStateCookieName() {
|
||||
return stateCookieName;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ public class ResourceMetadata {
|
|||
protected String clientKeyPassword;
|
||||
protected KeyStore truststore;
|
||||
protected PublicKey realmKey;
|
||||
protected String scope;
|
||||
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
|
@ -78,4 +79,12 @@ public class ResourceMetadata {
|
|||
public void setRealmKey(PublicKey realmKey) {
|
||||
this.realmKey = realmKey;
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(String scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
|||
"resource", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
"expose-token", "bearer-only",
|
||||
"expose-token", "bearer-only", "scope",
|
||||
"connection-pool-size",
|
||||
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
|
||||
"client-keystore", "client-keystore-password", "client-key-password"
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.representations.adapters.config;
|
|||
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
import org.keycloak.representations.SkeletonKeyScope;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -16,7 +17,7 @@ import java.util.Map;
|
|||
"resource", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
"expose-token", "bearer-only"})
|
||||
"expose-token", "bearer-only", "scope"})
|
||||
public class BaseAdapterConfig extends BaseRealmConfig {
|
||||
@JsonProperty("resource")
|
||||
protected String resource;
|
||||
|
@ -36,6 +37,9 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
|||
protected boolean bearerOnly;
|
||||
@JsonProperty("credentials")
|
||||
protected Map<String, String> credentials = new HashMap<String, String>();
|
||||
@JsonProperty("scope")
|
||||
protected SkeletonKeyScope scope;
|
||||
|
||||
|
||||
public boolean isUseResourceRoleMappings() {
|
||||
return useResourceRoleMappings;
|
||||
|
@ -108,4 +112,12 @@ public class BaseAdapterConfig extends BaseRealmConfig {
|
|||
public void setCredentials(Map<String, String> credentials) {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
public SkeletonKeyScope getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
public void setScope(SkeletonKeyScope scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,8 @@
|
|||
"ssl-not-required" : true,
|
||||
"credentials" : {
|
||||
"password" : "password"
|
||||
},
|
||||
"scope": {
|
||||
"realm": [ "user" ]
|
||||
}
|
||||
}
|
|
@ -2,7 +2,10 @@ package org.keycloak.adapters.config;
|
|||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.annotate.JsonSerialize;
|
||||
import org.keycloak.representations.SkeletonKeyScope;
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.util.EnvUtil;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.PemUtils;
|
||||
import org.keycloak.adapters.ResourceMetadata;
|
||||
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||
|
@ -64,6 +67,11 @@ public class AdapterConfigLoader {
|
|||
resourceMetadata.setClientKeyPassword(clientKeyPassword);
|
||||
resourceMetadata.setTruststore(this.truststore);
|
||||
|
||||
if (adapterConfig.getScope() != null) {
|
||||
String scope = encodeScope(adapterConfig.getScope());
|
||||
resourceMetadata.setScope(scope);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public AdapterConfig getAdapterConfig() {
|
||||
|
@ -119,4 +127,13 @@ public class AdapterConfigLoader {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String encodeScope(SkeletonKeyScope scope) {
|
||||
try {
|
||||
byte[] scopeBytes = JsonSerialization.writeValueAsBytes(scope);
|
||||
return Base64Url.encode(scopeBytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,5 +30,9 @@ public abstract class OAuthClientConfigLoader extends RealmConfigurationLoader {
|
|||
oauthClient.setAuthUrl(adapterConfig.getAuthUrl());
|
||||
oauthClient.setCodeUrl(adapterConfig.getCodeUrl());
|
||||
oauthClient.setTruststore(truststore);
|
||||
if (adapterConfig.getScope() != null) {
|
||||
String scope = encodeScope(adapterConfig.getScope());
|
||||
oauthClient.setScope(scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,12 +138,15 @@ public class ServletOAuthLogin {
|
|||
if (port != 443) secureUrl.port(port);
|
||||
url = secureUrl.build().toString();
|
||||
}
|
||||
return realmInfo.getAuthUrl().clone()
|
||||
KeycloakUriBuilder uriBuilder = realmInfo.getAuthUrl().clone()
|
||||
.queryParam("client_id", realmInfo.getMetadata().getResourceName())
|
||||
.queryParam("redirect_uri", url)
|
||||
.queryParam("state", state)
|
||||
.queryParam("login", "true")
|
||||
.build().toString();
|
||||
.queryParam("login", "true");
|
||||
if (realmInfo.getMetadata().getScope() != null) {
|
||||
uriBuilder.queryParam("scope", realmInfo.getMetadata().getScope());
|
||||
}
|
||||
return uriBuilder.build().toString();
|
||||
}
|
||||
|
||||
protected static final AtomicLong counter = new AtomicLong();
|
||||
|
|
|
@ -18,6 +18,7 @@ import javax.ws.rs.core.Response;
|
|||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Helper code to obtain oauth access tokens via browser redirects
|
||||
|
@ -87,11 +88,15 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
|
|||
state += "#" + path;
|
||||
}
|
||||
|
||||
URI url = UriBuilder.fromUri(authUrl)
|
||||
UriBuilder uriBuilder = UriBuilder.fromUri(authUrl)
|
||||
.queryParam("client_id", clientId)
|
||||
.queryParam("redirect_uri", redirectUri)
|
||||
.queryParam("state", state)
|
||||
.build();
|
||||
.queryParam("state", state);
|
||||
if (scope != null) {
|
||||
uriBuilder.queryParam("scope", scope);
|
||||
}
|
||||
URI url = uriBuilder.build();
|
||||
|
||||
NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true);
|
||||
logger.debug("NewCookie: " + cookie.toString());
|
||||
logger.debug("Oauth Redirect to: " + url);
|
||||
|
|
|
@ -84,11 +84,15 @@ public class ServletOAuthClient extends AbstractOAuthClient {
|
|||
public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String state = getStateCode();
|
||||
|
||||
URI url = KeycloakUriBuilder.fromUri(authUrl)
|
||||
KeycloakUriBuilder uriBuilder = KeycloakUriBuilder.fromUri(authUrl)
|
||||
.queryParam("client_id", clientId)
|
||||
.queryParam("redirect_uri", redirectUri)
|
||||
.queryParam("state", state)
|
||||
.build();
|
||||
.queryParam("state", state);
|
||||
if (scope != null) {
|
||||
uriBuilder.queryParam("scope", scope);
|
||||
}
|
||||
URI url = uriBuilder.build();
|
||||
|
||||
String stateCookiePath = this.stateCookiePath;
|
||||
if (stateCookiePath == null) stateCookiePath = request.getContextPath();
|
||||
if (stateCookiePath.equals("")) stateCookiePath = "/";
|
||||
|
|
Loading…
Reference in a new issue