oauth
This commit is contained in:
parent
4a40ec71c9
commit
579aefd310
3 changed files with 186 additions and 177 deletions
|
@ -1,8 +1,13 @@
|
||||||
package org.keycloak.services.managers;
|
package org.keycloak.services.managers;
|
||||||
|
|
||||||
import org.keycloak.representations.SkeletonKeyToken;
|
import org.keycloak.representations.SkeletonKeyToken;
|
||||||
|
import org.picketlink.idm.model.Role;
|
||||||
import org.picketlink.idm.model.User;
|
import org.picketlink.idm.model.User;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MultivaluedHashMap;
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,9 +16,13 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public class AccessCodeEntry {
|
public class AccessCodeEntry {
|
||||||
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
|
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
|
||||||
|
protected String code;
|
||||||
protected long expiration;
|
protected long expiration;
|
||||||
protected SkeletonKeyToken token;
|
protected SkeletonKeyToken token;
|
||||||
|
protected User user;
|
||||||
protected User client;
|
protected User client;
|
||||||
|
protected List<Role> realmRolesRequested = new ArrayList<Role>();
|
||||||
|
MultivaluedMap<String, Role> resourceRolesRequested = new MultivaluedHashMap<String, Role>();
|
||||||
|
|
||||||
public boolean isExpired() {
|
public boolean isExpired() {
|
||||||
return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
|
return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
|
||||||
|
@ -23,6 +32,14 @@ public class AccessCodeEntry {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCode(String code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
public long getExpiration() {
|
public long getExpiration() {
|
||||||
return expiration;
|
return expiration;
|
||||||
}
|
}
|
||||||
|
@ -46,4 +63,20 @@ public class AccessCodeEntry {
|
||||||
public void setClient(User client) {
|
public void setClient(User client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Role> getRealmRolesRequested() {
|
||||||
|
return realmRolesRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultivaluedMap<String, Role> getResourceRolesRequested() {
|
||||||
|
return resourceRolesRequested;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,16 @@ package org.keycloak.services.managers;
|
||||||
import org.jboss.resteasy.jose.Base64Url;
|
import org.jboss.resteasy.jose.Base64Url;
|
||||||
import org.jboss.resteasy.jose.jws.JWSBuilder;
|
import org.jboss.resteasy.jose.jws.JWSBuilder;
|
||||||
import org.jboss.resteasy.jwt.JsonSerialization;
|
import org.jboss.resteasy.jwt.JsonSerialization;
|
||||||
import org.jboss.resteasy.spi.HttpResponse;
|
|
||||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
|
||||||
import org.keycloak.representations.SkeletonKeyScope;
|
import org.keycloak.representations.SkeletonKeyScope;
|
||||||
import org.keycloak.representations.SkeletonKeyToken;
|
import org.keycloak.representations.SkeletonKeyToken;
|
||||||
import org.keycloak.services.models.RealmModel;
|
import org.keycloak.services.models.RealmModel;
|
||||||
import org.keycloak.services.models.ResourceModel;
|
import org.keycloak.services.models.ResourceModel;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
import org.picketlink.idm.model.Role;
|
||||||
import org.picketlink.idm.model.User;
|
import org.picketlink.idm.model.User;
|
||||||
|
|
||||||
import javax.ws.rs.ForbiddenException;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Cookie;
|
|
||||||
import javax.ws.rs.core.NewCookie;
|
import javax.ws.rs.core.NewCookie;
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -40,6 +37,9 @@ public class TokenManager {
|
||||||
accessCodeMap.clear();
|
accessCodeMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AccessCodeEntry getAccessCode(String key) {
|
||||||
|
return accessCodeMap.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
public AccessCodeEntry pullAccessCode(String key) {
|
public AccessCodeEntry pullAccessCode(String key) {
|
||||||
return accessCodeMap.remove(key);
|
return accessCodeMap.remove(key);
|
||||||
|
@ -54,16 +54,57 @@ public class TokenManager {
|
||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String createAccessCode(String scopeParam, RealmModel realm, User client, User user)
|
public AccessCodeEntry createAccessCode(String scopeParam, RealmModel realm, User client, User user) {
|
||||||
{
|
|
||||||
SkeletonKeyToken token = null;
|
|
||||||
if (scopeParam != null) token = createScopedToken(scopeParam, realm, client, user);
|
|
||||||
else token = createUnscopedToken(realm, client, user);
|
|
||||||
|
|
||||||
AccessCodeEntry code = new AccessCodeEntry();
|
AccessCodeEntry code = new AccessCodeEntry();
|
||||||
|
SkeletonKeyScope scopeMap = null;
|
||||||
|
if (scopeParam != null) scopeMap = decodeScope(scopeParam);
|
||||||
|
List<Role> realmRolesRequested = code.getRealmRolesRequested();
|
||||||
|
MultivaluedMap<String, Role> resourceRolesRequested = code.getResourceRolesRequested();
|
||||||
|
Set<String> realmMapping = realm.getRoleMappings(user);
|
||||||
|
|
||||||
|
if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
|
||||||
|
Set<String> scope = realm.getScope(client);
|
||||||
|
if (scope.size() > 0) {
|
||||||
|
Set<String> scopeRequest = null;
|
||||||
|
if (scopeMap != null) {
|
||||||
|
scopeRequest.addAll(scopeMap.get("realm"));
|
||||||
|
if (scopeRequest.contains(RealmManager.WILDCARD_ROLE)) scopeRequest = null;
|
||||||
|
}
|
||||||
|
for (String role : realmMapping) {
|
||||||
|
if (
|
||||||
|
(scopeRequest == null || scopeRequest.contains(role)) &&
|
||||||
|
(scope.contains("*") || scope.contains(role))
|
||||||
|
)
|
||||||
|
realmRolesRequested.add(realm.getIdm().getRole(role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ResourceModel resource : realm.getResources()) {
|
||||||
|
Set<String> mapping = resource.getRoleMappings(user);
|
||||||
|
if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
|
||||||
|
Set<String> scope = resource.getScope(client);
|
||||||
|
if (scope.size() > 0) {
|
||||||
|
Set<String> scopeRequest = null;
|
||||||
|
if (scopeMap != null) {
|
||||||
|
scopeRequest.addAll(scopeMap.get(resource.getName()));
|
||||||
|
if (scopeRequest.contains(RealmManager.WILDCARD_ROLE)) scopeRequest = null;
|
||||||
|
}
|
||||||
|
for (String role : mapping) {
|
||||||
|
if (
|
||||||
|
(scopeRequest == null || scopeRequest.contains(role)) &&
|
||||||
|
(scope.contains("*") || scope.contains(role))
|
||||||
|
)
|
||||||
|
resourceRolesRequested.add(resource.getName(), resource.getIdm().getRole(role));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
createToken(code, realm, client, user);
|
||||||
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
||||||
code.setToken(token);
|
|
||||||
code.setClient(client);
|
code.setClient(client);
|
||||||
|
code.setUser(user);
|
||||||
accessCodeMap.put(code.getId(), code);
|
accessCodeMap.put(code.getId(), code);
|
||||||
String accessCode = null;
|
String accessCode = null;
|
||||||
try {
|
try {
|
||||||
|
@ -71,30 +112,8 @@ public class TokenManager {
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return accessCode;
|
code.setCode(accessCode);
|
||||||
}
|
return code;
|
||||||
|
|
||||||
public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
|
|
||||||
SkeletonKeyToken token = initToken(realm, client, user);
|
|
||||||
Map<String, ResourceModel> resourceMap = realm.getResourceMap();
|
|
||||||
|
|
||||||
for (String res : scope.keySet()) {
|
|
||||||
ResourceModel resource = resourceMap.get(res);
|
|
||||||
Set<String> scopeMapping = resource.getScope(client);
|
|
||||||
Set<String> roleMapping = resource.getRoleMappings(user);
|
|
||||||
SkeletonKeyToken.Access access = token.addAccess(resource.getName());
|
|
||||||
for (String role : scope.get(res)) {
|
|
||||||
if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
|
|
||||||
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
|
|
||||||
}
|
|
||||||
if (!roleMapping.contains(role)) {
|
|
||||||
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
|
|
||||||
|
|
||||||
}
|
|
||||||
access.addRole(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SkeletonKeyToken initToken(RealmModel realm, User client, User user) {
|
protected SkeletonKeyToken initToken(RealmModel realm, User client, User user) {
|
||||||
|
@ -110,38 +129,29 @@ public class TokenManager {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) {
|
protected void createToken(AccessCodeEntry accessCodeEntry, RealmModel realm, User client, User user) {
|
||||||
SkeletonKeyScope scope = decodeScope(scopeParam);
|
|
||||||
return createScopedToken(scope, realm, client, user);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SkeletonKeyToken createUnscopedToken(RealmModel realm, User client, User user) {
|
|
||||||
|
|
||||||
SkeletonKeyToken token = initToken(realm, client, user);
|
SkeletonKeyToken token = initToken(realm, client, user);
|
||||||
|
|
||||||
Set<String> realmMapping = realm.getRoleMappings(user);
|
if (accessCodeEntry.getRealmRolesRequested().size() > 0) {
|
||||||
|
|
||||||
if (realmMapping != null && realmMapping.size() > 0) {
|
|
||||||
Set<String> scope = realm.getScope(client);
|
|
||||||
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
|
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
|
||||||
for (String role : realmMapping) {
|
for (Role role : accessCodeEntry.getRealmRolesRequested()) {
|
||||||
if (scope.contains("*") || scope.contains(role)) access.addRole(role);
|
access.addRole(role.getName());
|
||||||
}
|
}
|
||||||
token.setRealmAccess(access);
|
token.setRealmAccess(access);
|
||||||
}
|
}
|
||||||
List<ResourceModel> resources = realm.getResources();
|
|
||||||
for (ResourceModel resource : resources) {
|
if (accessCodeEntry.getResourceRolesRequested().size() > 0) {
|
||||||
Set<String> scope = resource.getScope(client);
|
Map<String, ResourceModel> resourceMap = realm.getResourceMap();
|
||||||
Set<String> mapping = resource.getRoleMappings(user);
|
for (String resourceName : accessCodeEntry.getResourceRolesRequested().keySet()) {
|
||||||
if (mapping.size() == 0 || scope.size() == 0) continue;
|
ResourceModel resource = resourceMap.get(resourceName);
|
||||||
SkeletonKeyToken.Access access = token.addAccess(resource.getName())
|
SkeletonKeyToken.Access access = token.addAccess(resourceName).verifyCaller(resource.isSurrogateAuthRequired());
|
||||||
.verifyCaller(resource.isSurrogateAuthRequired());
|
for (Role role : accessCodeEntry.getResourceRolesRequested().get(resourceName)) {
|
||||||
for (String role : mapping) {
|
access.addRole(role.getName());
|
||||||
if (scope.contains("*") || scope.contains(role)) access.addRole(role);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return token;
|
accessCodeEntry.setToken(token);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String encodeScope(SkeletonKeyScope scope) {
|
public String encodeScope(SkeletonKeyScope scope) {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package org.keycloak.services.resources;
|
package org.keycloak.services.resources;
|
||||||
|
|
||||||
import org.jboss.resteasy.jose.Base64Url;
|
|
||||||
import org.jboss.resteasy.jose.jws.JWSBuilder;
|
import org.jboss.resteasy.jose.jws.JWSBuilder;
|
||||||
import org.jboss.resteasy.jose.jws.JWSInput;
|
import org.jboss.resteasy.jose.jws.JWSInput;
|
||||||
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
|
import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
|
||||||
import org.jboss.resteasy.jwt.JsonSerialization;
|
import org.jboss.resteasy.jwt.JsonSerialization;
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
import org.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
|
import org.jboss.resteasy.spi.HttpResponse;
|
||||||
|
import org.keycloak.TokenIdGenerator;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.SkeletonKeyScope;
|
import org.keycloak.representations.SkeletonKeyScope;
|
||||||
import org.keycloak.representations.SkeletonKeyToken;
|
import org.keycloak.representations.SkeletonKeyToken;
|
||||||
|
@ -17,7 +18,6 @@ import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.services.managers.ResourceAdminManager;
|
import org.keycloak.services.managers.ResourceAdminManager;
|
||||||
import org.keycloak.services.managers.TokenManager;
|
import org.keycloak.services.managers.TokenManager;
|
||||||
import org.keycloak.services.models.RealmModel;
|
import org.keycloak.services.models.RealmModel;
|
||||||
import org.keycloak.services.models.RequiredCredentialModel;
|
|
||||||
import org.keycloak.services.models.ResourceModel;
|
import org.keycloak.services.models.ResourceModel;
|
||||||
import org.picketlink.idm.IdentitySession;
|
import org.picketlink.idm.IdentitySession;
|
||||||
import org.picketlink.idm.model.Role;
|
import org.picketlink.idm.model.Role;
|
||||||
|
@ -31,15 +31,20 @@ import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.QueryParam;
|
import javax.ws.rs.QueryParam;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.Cookie;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.MultivaluedHashMap;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.NewCookie;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.SecurityContext;
|
import javax.ws.rs.core.SecurityContext;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import javax.ws.rs.ext.Providers;
|
import javax.ws.rs.ext.Providers;
|
||||||
|
import java.net.URI;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -66,10 +71,13 @@ public class TokenService {
|
||||||
protected IdentitySession identitySession;
|
protected IdentitySession identitySession;
|
||||||
@Context
|
@Context
|
||||||
HttpRequest request;
|
HttpRequest request;
|
||||||
|
@Context
|
||||||
|
HttpResponse response;
|
||||||
|
|
||||||
|
|
||||||
protected String securityFailurePath = "/securityFailure.jsp";
|
protected String securityFailurePath = "/securityFailure.jsp";
|
||||||
protected String loginFormPath = "/loginForm.jsp";
|
protected String loginFormPath = "/loginForm.jsp";
|
||||||
|
protected String oauthFormPath = "/oauthForm.jsp";
|
||||||
|
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
protected TokenManager tokenManager;
|
protected TokenManager tokenManager;
|
||||||
|
@ -110,6 +118,10 @@ public class TokenService {
|
||||||
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processLogin");
|
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processLogin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UriBuilder processOAuthUrl(UriInfo uriInfo) {
|
||||||
|
return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processOAuth");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Path("grants/identity-token")
|
@Path("grants/identity-token")
|
||||||
@POST
|
@POST
|
||||||
|
@ -211,16 +223,35 @@ public class TokenService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirectAccessCode(scopeParam, state, redirect, client, user);
|
return processAccessCode(scopeParam, state, redirect, client, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Response redirectAccessCode(String scopeParam, String state, String redirect, User client, User user) {
|
protected Response processAccessCode(String scopeParam, String state, String redirect, User client, User user) {
|
||||||
String accessCode = tokenManager.createAccessCode(scopeParam, realm, client, user);
|
Role resourceRole = realm.getIdm().getRole(RealmManager.RESOURCE_ROLE);
|
||||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
|
Role oauthClientRole = realm.getIdm().getRole(RealmManager.OAUTH_CLIENT_ROLE);
|
||||||
|
boolean isResource = realm.getIdm().hasRole(client, resourceRole);
|
||||||
|
if (!isResource && !realm.getIdm().hasRole(client, oauthClientRole)) {
|
||||||
|
securityFailureForward("Login requester not allowed to request login.");
|
||||||
|
identitySession.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, realm, client, user);
|
||||||
|
|
||||||
|
if (!isResource && accessCode.getRealmRolesRequested().size() > 0 && accessCode.getResourceRolesRequested().size() > 0) {
|
||||||
|
oauthGrantPage(accessCode, client, state, redirect);
|
||||||
|
identitySession.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return redirectAccessCode(accessCode, state, redirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect) {
|
||||||
|
String code = accessCode.getCode();
|
||||||
|
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||||
if (state != null) redirectUri.queryParam("state", state);
|
if (state != null) redirectUri.queryParam("state", state);
|
||||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||||
if (realm.isCookieLoginAllowed()) {
|
if (realm.isCookieLoginAllowed()) {
|
||||||
location.cookie(tokenManager.createLoginCookie(realm, user, uriInfo));
|
location.cookie(tokenManager.createLoginCookie(realm, accessCode.getUser(), uriInfo));
|
||||||
}
|
}
|
||||||
return location.build();
|
return location.build();
|
||||||
}
|
}
|
||||||
|
@ -393,16 +424,16 @@ public class TokenService {
|
||||||
}
|
}
|
||||||
Role resourceRole = realm.getIdm().getRole(RealmManager.RESOURCE_ROLE);
|
Role resourceRole = realm.getIdm().getRole(RealmManager.RESOURCE_ROLE);
|
||||||
Role oauthClientRole = realm.getIdm().getRole(RealmManager.OAUTH_CLIENT_ROLE);
|
Role oauthClientRole = realm.getIdm().getRole(RealmManager.OAUTH_CLIENT_ROLE);
|
||||||
if (!realm.getIdm().hasRole(client, resourceRole) && !realm.getIdm().hasRole(client, oauthClientRole)) {
|
boolean isResource = realm.getIdm().hasRole(client, resourceRole);
|
||||||
|
if (!isResource && !realm.getIdm().hasRole(client, oauthClientRole)) {
|
||||||
securityFailureForward("Login requester not allowed to request login.");
|
securityFailureForward("Login requester not allowed to request login.");
|
||||||
identitySession.close();
|
identitySession.close();
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
return redirectAccessCode(scopeParam, state, redirect, client, user);
|
return processAccessCode(scopeParam, state, redirect, client, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
forwardToLoginForm(redirect, clientId, scopeParam, state);
|
forwardToLoginForm(redirect, clientId, scopeParam, state);
|
||||||
|
@ -424,117 +455,52 @@ public class TokenService {
|
||||||
return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
|
return Response.status(302).location(UriBuilder.fromUri(redirectUri).build()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
|
@Path("oauth/grant")
|
||||||
StringBuffer html = new StringBuffer();
|
@POST
|
||||||
if (scopeParam != null) {
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
|
public Response processOAuth(MultivaluedMap<String, String> formData) {
|
||||||
if (validationError != null) {
|
String redirect = formData.getFirst("redirect_uri");
|
||||||
try {
|
String state = formData.getFirst("state");
|
||||||
Thread.sleep(1000); // put in a delay
|
if (formData.containsKey("cancel")) {
|
||||||
} catch (InterruptedException e) {
|
return redirectAccessDenied(redirect, state);
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
html.append("<p/><p><b>").append(validationError).append("</b></p>");
|
|
||||||
}
|
|
||||||
html.append("<p>A Third Party is requesting access to the following resources</p>");
|
|
||||||
html.append("<table>");
|
|
||||||
SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
|
|
||||||
Map<String, ResourceModel> resourceMap = realm.getResourceMap();
|
|
||||||
|
|
||||||
for (String res : scope.keySet()) {
|
|
||||||
ResourceModel resource = resourceMap.get(res);
|
|
||||||
html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
|
|
||||||
Set<String> scopeMapping = resource.getScope(client);
|
|
||||||
for (String role : scope.get(res)) {
|
|
||||||
html.append(" ").append(role);
|
|
||||||
if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
|
|
||||||
return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
html.append("</td></tr>");
|
|
||||||
}
|
|
||||||
html.append("</table><p>To Authorize, please login below</p>");
|
|
||||||
} else {
|
|
||||||
Set<String> scopeMapping = realm.getScope(client);
|
|
||||||
if (scopeMapping.contains("*")) {
|
|
||||||
html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
|
|
||||||
if (validationError != null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000); // put in a delay
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
html.append("<p/><p><b>").append(validationError).append("</b></p>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
|
|
||||||
if (validationError != null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000); // put in a delay
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
html.append("<p/><p><b>").append(validationError).append("</b></p>");
|
|
||||||
}
|
|
||||||
SkeletonKeyScope scope = new SkeletonKeyScope();
|
|
||||||
List<ResourceModel> resources = realm.getResources();
|
|
||||||
boolean found = false;
|
|
||||||
for (ResourceModel resource : resources) {
|
|
||||||
Set<String> resourceScope = resource.getScope(client);
|
|
||||||
if (resourceScope == null) continue;
|
|
||||||
if (resourceScope.size() == 0) continue;
|
|
||||||
if (!found) {
|
|
||||||
found = true;
|
|
||||||
html.append("<p>A Third Party is requesting access to the following resources</p>");
|
|
||||||
html.append("<table>");
|
|
||||||
}
|
|
||||||
html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
|
|
||||||
// todo add description of role
|
|
||||||
for (String role : resourceScope) {
|
|
||||||
html.append(" ").append(role);
|
|
||||||
scope.add(resource.getName(), role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
|
|
||||||
}
|
|
||||||
html.append("</table>");
|
|
||||||
try {
|
|
||||||
String json = JsonSerialization.toString(scope, false);
|
|
||||||
scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
String code = formData.getFirst("code");
|
||||||
|
|
||||||
UriBuilder formActionUri = processLoginUrl(uriInfo);
|
JWSInput input = new JWSInput(code, providers);
|
||||||
String action = formActionUri.build(realm.getId()).toString();
|
boolean verifiedCode = false;
|
||||||
html.append("<form action=\"").append(action).append("\" method=\"POST\">");
|
try {
|
||||||
html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
|
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
||||||
|
} catch (Exception ignored) {
|
||||||
for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
|
logger.debug("Failed to verify signature", ignored);
|
||||||
if (!credential.isInput()) continue;
|
|
||||||
html.append(credential.getType()).append(": ");
|
|
||||||
if (credential.isSecret()) {
|
|
||||||
html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
|
if (!verifiedCode) {
|
||||||
if (scopeParam != null) {
|
return redirectAccessDenied(redirect, state);
|
||||||
html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
|
|
||||||
}
|
}
|
||||||
if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");
|
String key = input.readContent(String.class);
|
||||||
html.append("<input type=\"hidden\" name=\"redirect_uri\" value=\"").append(redirect).append("\">");
|
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
|
||||||
html.append("<input type=\"submit\" value=\"");
|
if (accessCodeEntry == null) {
|
||||||
if (scopeParam == null) html.append("Login");
|
return redirectAccessDenied(redirect, state);
|
||||||
else html.append("Grant Access");
|
}
|
||||||
html.append("\">");
|
return redirectAccessCode(accessCodeEntry, state, redirect);
|
||||||
html.append("</form>");
|
|
||||||
return Response.ok(html.toString()).type("text/html").build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Response redirectAccessDenied(String redirect, String state) {
|
||||||
|
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("error", "access_denied");
|
||||||
|
if (state != null) redirectUri.queryParam("state", state);
|
||||||
|
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||||
|
return location.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void oauthGrantPage(AccessCodeEntry accessCode, User client, String state, String redirect_uri) {
|
||||||
|
request.setAttribute("realmRolesRequested", accessCode.getRealmRolesRequested());
|
||||||
|
request.setAttribute("resourceRolesRequested", accessCode.getResourceRolesRequested());
|
||||||
|
request.setAttribute("state", state);
|
||||||
|
request.setAttribute("redirect_uri", redirect_uri);
|
||||||
|
request.setAttribute("client", client);
|
||||||
|
request.setAttribute("action", processOAuthUrl(uriInfo));
|
||||||
|
request.setAttribute("accessCode", accessCode.getCode());
|
||||||
|
|
||||||
|
request.forward(oauthFormPath);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue