Merge pull request #11 from patriot1burke/master

logout
This commit is contained in:
Bill Burke 2013-07-27 15:21:42 -07:00
commit 1be8136347
33 changed files with 551 additions and 236 deletions

View file

@ -15,8 +15,7 @@ public class RealmConfiguration {
protected ResteasyClient client; protected ResteasyClient client;
protected UriBuilder authUrl; protected UriBuilder authUrl;
protected ResteasyWebTarget codeUrl; protected ResteasyWebTarget codeUrl;
protected String clientId; protected Form resourceCredentials = new Form();
protected Form credentials = new Form();
protected boolean sslRequired = true; protected boolean sslRequired = true;
protected String stateCookieName = "OAuth_Token_Request_State"; protected String stateCookieName = "OAuth_Token_Request_State";
@ -44,16 +43,8 @@ public class RealmConfiguration {
this.authUrl = authUrl; this.authUrl = authUrl;
} }
public String getClientId() { public Form getResourceCredentials() {
return clientId; return resourceCredentials;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public Form getCredentials() {
return credentials;
} }
public ResteasyWebTarget getCodeUrl() { public ResteasyWebTarget getCodeUrl() {

View file

@ -8,8 +8,8 @@ import java.security.PublicKey;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ResourceMetadata { public class ResourceMetadata {
protected String resourceName;
protected String realm; protected String realm;
protected String resourceName;
protected KeyStore clientKeystore; protected KeyStore clientKeystore;
protected String clientKeyPassword; protected String clientKeyPassword;
protected KeyStore truststore; protected KeyStore truststore;

View file

@ -0,0 +1,15 @@
package org.keycloak;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class TokenIdGenerator {
private static final AtomicLong counter = new AtomicLong();
public static String generateId() {
return UUID.randomUUID().toString() + "-" + System.currentTimeMillis();
}
}

View file

@ -0,0 +1,35 @@
package org.keycloak.representations.idm;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CredentialRepresentation {
protected String type;
protected String value;
protected boolean hashed;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public boolean isHashed() {
return hashed;
}
public void setHashed(boolean hashed) {
this.hashed = hashed;
}
}

View file

@ -12,7 +12,10 @@ import java.util.Set;
public class ResourceRepresentation { public class ResourceRepresentation {
protected String self; // link protected String self; // link
protected String name; protected String name;
protected String adminUrl;
protected boolean surrogateAuthRequired; protected boolean surrogateAuthRequired;
protected boolean useRealmMappings;
protected List<CredentialRepresentation> credentials;
protected Set<String> roles; protected Set<String> roles;
protected List<RoleMappingRepresentation> roleMappings; protected List<RoleMappingRepresentation> roleMappings;
protected List<ScopeMappingRepresentation> scopeMappings; protected List<ScopeMappingRepresentation> scopeMappings;
@ -79,5 +82,37 @@ public class ResourceRepresentation {
return mapping; return mapping;
} }
public String getAdminUrl() {
return adminUrl;
}
public void setAdminUrl(String adminUrl) {
this.adminUrl = adminUrl;
}
public List<CredentialRepresentation> getCredentials() {
return credentials;
}
public void setCredentials(List<CredentialRepresentation> credentials) {
this.credentials = credentials;
}
public ResourceRepresentation credential(String type, String value, boolean hashed) {
if (this.credentials == null) credentials = new ArrayList<CredentialRepresentation>();
CredentialRepresentation cred = new CredentialRepresentation();
cred.setType(type);
cred.setValue(value);
cred.setHashed(hashed);
credentials.add(cred);
return this;
}
public boolean isUseRealmMappings() {
return useRealmMappings;
}
public void setUseRealmMappings(boolean useRealmMappings) {
this.useRealmMappings = useRealmMappings;
}
} }

View file

@ -10,41 +10,12 @@ import java.util.Map;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class UserRepresentation { public class UserRepresentation {
public static class Credential {
protected String type;
protected String value;
protected boolean hashed;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public boolean isHashed() {
return hashed;
}
public void setHashed(boolean hashed) {
this.hashed = hashed;
}
}
protected String self; // link protected String self; // link
protected String username; protected String username;
protected boolean enabled; protected boolean enabled;
protected Map<String, String> attributes; protected Map<String, String> attributes;
protected List<Credential> credentials; protected List<CredentialRepresentation> credentials;
public String getSelf() { public String getSelf() {
return self; return self;
@ -70,23 +41,23 @@ public class UserRepresentation {
this.attributes = attributes; this.attributes = attributes;
} }
public List<Credential> getCredentials() {
return credentials;
}
public void setCredentials(List<Credential> credentials) {
this.credentials = credentials;
}
public UserRepresentation attribute(String name, String value) { public UserRepresentation attribute(String name, String value) {
if (this.attributes == null) attributes = new HashMap<String, String>(); if (this.attributes == null) attributes = new HashMap<String, String>();
attributes.put(name, value); attributes.put(name, value);
return this; return this;
} }
public List<CredentialRepresentation> getCredentials() {
return credentials;
}
public void setCredentials(List<CredentialRepresentation> credentials) {
this.credentials = credentials;
}
public UserRepresentation credential(String type, String value, boolean hashed) { public UserRepresentation credential(String type, String value, boolean hashed) {
if (this.credentials == null) credentials = new ArrayList<Credential>(); if (this.credentials == null) credentials = new ArrayList<CredentialRepresentation>();
Credential cred = new Credential(); CredentialRepresentation cred = new CredentialRepresentation();
cred.setType(type); cred.setType(type);
cred.setValue(value); cred.setValue(value);
cred.setHashed(hashed); cred.setHashed(hashed);

View file

@ -0,0 +1,66 @@
package org.keycloak.representations.idm.admin;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* Posted to managed client from admin server.
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AdminAction {
protected String id;
protected long expiration;
protected String resource;
protected String action;
public AdminAction() {
}
public AdminAction(String id, long expiration, String resource, String action) {
this.id = id;
this.expiration = expiration;
this.resource = resource;
this.action = action;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
@JsonIgnore
public boolean isExpired()
{
long time = System.currentTimeMillis() / 1000;
return time > expiration;
}
public long getExpiration() {
return expiration;
}
public void setExpiration(long expiration) {
this.expiration = expiration;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
}

View file

@ -0,0 +1,26 @@
package org.keycloak.representations.idm.admin;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class LogoutAction extends AdminAction {
public static final String LOGOUT_ACTION = "logout";
protected String user;
public LogoutAction() {
}
public LogoutAction(String id, long expiration, String resource, String user) {
super(id, expiration, resource, LOGOUT_ACTION);
this.user = user;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}

View file

@ -1,11 +1,11 @@
{ {
"realm" : "demo", "realm" : "demo",
"resource" : "customer-portal",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login", "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
"code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes", "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
"ssl-not-required" : true, "ssl-not-required" : true,
"client-id" : "customer-portal", "credentials" : {
"client-credentials" : {
"password" : "password" "password" : "password"
} }
} }

View file

@ -1,11 +1,15 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<html> <html>
<head> <head>
<title>Customer View Page</title> <title>Customer View Page</title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">
<p>Goto: <a href="https://localhost:8443/product-portal">products</a> | <a href="https://localhost:8443/auth-server/j_oauth_logout">logout</a></p> <%
String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
.queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
%>
<p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a></p>
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Customer Listing</h2> <h2>Customer Listing</h2>
<% <%

View file

@ -1,4 +1,5 @@
{ {
"realm" : "demo", "realm" : "demo",
"resource" : "database-service",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB" "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"
} }

View file

@ -1,11 +1,11 @@
{ {
"realm" : "demo", "realm" : "demo",
"resource" : "product-portal",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login", "auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
"code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes", "code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
"ssl-not-required" : true, "ssl-not-required" : true,
"client-id" : "product-portal", "credentials" : {
"client-credentials" : {
"password" : "password" "password" : "password"
} }
} }

View file

@ -1,11 +1,16 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<html> <html>
<head> <head>
<title>Product View Page</title> <title>Product View Page</title>
</head> </head>
<body bgcolor="#F5F6CE"> <body bgcolor="#F5F6CE">
<p>Goto: <a href="https://localhost:8443/customer-portal">customers</a> | <a href="https://localhost:8443/auth-server/j_oauth_logout">logout</a></p> <%
String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
.queryParam("redirect_uri", "http://localhost:8080/product-portal").build().toString();
%>
<p>Goto: <a href="http://localhost:8080/customer-portal">customers</a> | <a href="<%=logoutUri%>">logout</a></p>
User <b><%=request.getUserPrincipal().getName()%></b> made this request. User <b><%=request.getUserPrincipal().getName()%></b> made this request.
<h2>Product Listing</h2> <h2>Product Listing</h2>
<% <%

View file

@ -25,22 +25,6 @@
{ "type" : "Password", { "type" : "Password",
"value" : "password" } "value" : "password" }
] ]
},
{
"username" : "customer-portal",
"enabled" : true,
"credentials" : [
{ "type" : "Password",
"value" : "password" }
]
},
{
"username" : "product-portal",
"enabled" : true,
"credentials" : [
{ "type" : "Password",
"value" : "password" }
]
} }
], ],
"roleMappings" : [ "roleMappings" : [
@ -49,14 +33,24 @@
"roles" : ["user"] "roles" : ["user"]
} }
], ],
"scopeMappings" : [ "resources" : [
{ {
"username" : "customer-portal", "name" : "customer-portal",
"roles" : ["*"] "adminUrl" : "http://localhost:8080/customer-portal/j_admin_request",
"useRealmMappings" : true,
"credentials" : [
{ "type" : "Password",
"value" : "password" }
]
}, },
{ {
"username" : "product-portal", "name" : "product-portal",
"roles" : ["*"] "adminUrl" : "http://localhost:8080/product-portal/j_admin_request",
"useRealmMappings" : true,
"credentials" : [
{ "type" : "Password",
"value" : "password" }
]
} }
] ]
} }

View file

@ -63,7 +63,7 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements
@Override @Override
protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException { protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
try { try {
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
if (bearer.login(request, response)) { if (bearer.login(request, response)) {
return true; return true;
} }

View file

@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.security.Principal; import java.security.Principal;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
@ -29,11 +30,13 @@ public class CatalinaBearerTokenAuthenticator {
protected SkeletonKeyToken token; protected SkeletonKeyToken token;
private Principal principal; private Principal principal;
protected boolean propagateToken; protected boolean propagateToken;
protected boolean useResourceRoleMappings;
public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge) { public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge, boolean useResourceRoleMappings) {
this.resourceMetadata = resourceMetadata; this.resourceMetadata = resourceMetadata;
this.challenge = challenge; this.challenge = challenge;
this.propagateToken = propagateToken; this.propagateToken = propagateToken;
this.useResourceRoleMappings = useResourceRoleMappings;
} }
public ResourceMetadata getResourceMetadata() { public ResourceMetadata getResourceMetadata() {
@ -77,8 +80,8 @@ public class CatalinaBearerTokenAuthenticator {
challengeResponse(response, "invalid_token", e.getMessage()); challengeResponse(response, "invalid_token", e.getMessage());
} }
boolean verifyCaller = false; boolean verifyCaller = false;
Set<String> roles = null; Set<String> roles = new HashSet<String>();
if (resourceMetadata.getResourceName() != null) { if (useResourceRoleMappings) {
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (access != null) roles = access.getRoles(); if (access != null) roles = access.getRoles();
verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName()); verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());

View file

@ -527,8 +527,8 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
html.append("<br>"); html.append("<br>");
writer = new StringWriter(); writer = new StringWriter();
rep.getClientCredentials().put("password", "REQUIRED"); rep.getCredentials().put("password", "REQUIRED");
rep.setClientId("REQUIRED"); //rep.setClientId("REQUIRED");
rep.setTruststore("REQUIRED"); rep.setTruststore("REQUIRED");
rep.setTruststorePassword("REQUIRED"); rep.setTruststorePassword("REQUIRED");
mapper.writeValue(writer, rep); mapper.writeValue(writer, rep);
@ -561,7 +561,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException { public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException {
if (request.getHeader("Authorization") != null) { if (request.getHeader("Authorization") != null) {
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false, false);
try { try {
if (bearer.login(request, response)) { if (bearer.login(request, response)) {
return true; return true;

View file

@ -14,8 +14,9 @@ import org.apache.catalina.deploy.LoginConfig;
import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.realm.GenericPrincipal;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.jose.jws.JWSInput;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.RealmConfiguration; import org.keycloak.RealmConfiguration;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
@ -24,12 +25,14 @@ import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.as7.config.ManagedResourceConfig; import org.keycloak.adapters.as7.config.ManagedResourceConfig;
import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader; import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.representations.idm.admin.LogoutAction;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -67,10 +70,6 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
managedResourceConfigLoader.init(true); managedResourceConfigLoader.init(true);
resourceMetadata = managedResourceConfigLoader.getResourceMetadata(); resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig(); remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
String client_id = remoteSkeletonKeyConfig.getClientId();
if (client_id == null) {
throw new IllegalArgumentException("Must set client-id to use with auth server");
}
realmConfiguration = new RealmConfiguration(); realmConfiguration = new RealmConfiguration();
String authUrl = remoteSkeletonKeyConfig.getAuthUrl(); String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
if (authUrl == null) { if (authUrl == null) {
@ -81,17 +80,16 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
throw new RuntimeException("You mut specify code-url"); throw new RuntimeException("You mut specify code-url");
} }
realmConfiguration.setMetadata(resourceMetadata); realmConfiguration.setMetadata(resourceMetadata);
realmConfiguration.setClientId(client_id);
realmConfiguration.setSslRequired(!remoteSkeletonKeyConfig.isSslNotRequired()); realmConfiguration.setSslRequired(!remoteSkeletonKeyConfig.isSslNotRequired());
for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet()) { for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getCredentials().entrySet()) {
realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue()); realmConfiguration.getResourceCredentials().param(entry.getKey(), entry.getValue());
} }
ResteasyClient client = managedResourceConfigLoader.getClient(); ResteasyClient client = managedResourceConfigLoader.getClient();
realmConfiguration.setClient(client); realmConfiguration.setClient(client);
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id)); realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
realmConfiguration.setCodeUrl(client.target(tokenUrl)); realmConfiguration.setCodeUrl(client.target(tokenUrl));
} }
@ -99,8 +97,8 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
public void invoke(Request request, Response response) throws IOException, ServletException { public void invoke(Request request, Response response) throws IOException, ServletException {
try { try {
String requestURI = request.getDecodedRequestURI(); String requestURI = request.getDecodedRequestURI();
if (requestURI.endsWith("j_oauth_remote_logout")) { if (requestURI.endsWith("j_admin_request")) {
remoteLogout(request, response); adminRequest(request, response);
return; return;
} }
super.invoke(request, response); super.invoke(request, response);
@ -135,33 +133,71 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
return false; return false;
} }
protected void remoteLogout(Request request, HttpServletResponse response) throws IOException { protected void adminRequest(Request request, HttpServletResponse response) throws IOException {
String token = request.getParameter("token");
if (token == null) {
log.warn("admin request failed, no token");
response.sendError(403, "no token");
return;
}
JWSInput input = new JWSInput(token);
boolean verified = false;
try {
verified = RSAProvider.verify(input, resourceMetadata.getRealmKey());
} catch (Exception ignore) {
}
if (!verified) {
log.warn("admin request failed, unable to verify token");
response.sendError(403, "verification failed");
return;
}
String action = request.getParameter("action");
if (LogoutAction.LOGOUT_ACTION.equals(action)) {
remoteLogout(input, response);
} else {
log.warn("admin request failed, unknown action");
response.sendError(403, "Unknown action");
}
}
protected void remoteLogout(JWSInput token, HttpServletResponse response) throws IOException {
try { try {
log.debug("->> remoteLogout: "); log.debug("->> remoteLogout: ");
if (!bearer(true, request, response)) { LogoutAction action = JsonSerialization.fromBytes(LogoutAction.class, token.getContent());
log.debug("remoteLogout: bearer auth failed"); if (action.isExpired()) {
log.warn("admin request failed, expired token");
response.sendError(400, "Expired token");
return; return;
} }
GenericPrincipal gp = (GenericPrincipal) request.getPrincipal(); if (!LogoutAction.LOGOUT_ACTION.equals(action.getAction())) {
if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole())) { log.warn("Action doesn't match");
log.debug("remoteLogout: role failure"); response.sendError(400, "Action does not match");
response.sendError(403);
return; return;
} }
String user = request.getParameter("user"); if (!resourceMetadata.getResourceName().equals(action.getResource())) {
log.warn("Resource name does not match");
response.sendError(400, "Resource name does not match");
return;
}
String user = action.getUser();
if (user != null) { if (user != null) {
log.info("logout of session for: " + user);
userSessionManagement.logout(user); userSessionManagement.logout(user);
} else { } else {
log.info("logout of all sessions");
userSessionManagement.logoutAll(); userSessionManagement.logoutAll();
} }
} catch (Exception e) { } catch (Exception e) {
log.error("failed to logout", e); log.warn("failed to logout", e);
response.sendError(500, "Failed to logout");
} }
response.setStatus(204); response.setStatus(204);
} }
protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException { protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException {
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
if (bearer.login(request, response)) { if (bearer.login(request, response)) {
return true; return true;
} }
@ -207,13 +243,13 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
if (!oauth.resolveCode(code)) return; if (!oauth.resolveCode(code)) return;
SkeletonKeyToken token = oauth.getToken(); SkeletonKeyToken token = oauth.getToken();
Set<String> roles = null; Set<String> roles = new HashSet<String>();
if (resourceMetadata.getResourceName() != null) { if (remoteSkeletonKeyConfig.isUseResourceRoleMappings()) {
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (access != null) roles = access.getRoles(); if (access != null) roles.addAll(access.getRoles());
} else { } else {
SkeletonKeyToken.Access access = token.getRealmAccess(); SkeletonKeyToken.Access access = token.getRealmAccess();
if (access != null) roles = access.getRoles(); if (access != null) roles.addAll(access.getRoles());
} }
SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null); SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles); GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);

View file

@ -1,7 +1,6 @@
package org.keycloak.adapters.as7; package org.keycloak.adapters.as7;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.util.BasicAuthHelper;
import org.keycloak.RSATokenVerifier; import org.keycloak.RSATokenVerifier;
import org.keycloak.RealmConfiguration; import org.keycloak.RealmConfiguration;
import org.keycloak.VerificationException; import org.keycloak.VerificationException;
@ -14,7 +13,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form; import javax.ws.rs.core.Form;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.io.IOException; import java.io.IOException;
@ -144,7 +142,7 @@ public class ServletOAuthLogin {
url = secureUrl.build().toString(); url = secureUrl.build().toString();
} }
return realmInfo.getAuthUrl().clone() return realmInfo.getAuthUrl().clone()
.queryParam("client_id", realmInfo.getClientId()) .queryParam("client_id", realmInfo.getMetadata().getResourceName())
.queryParam("redirect_uri", url) .queryParam("redirect_uri", url)
.queryParam("state", state) .queryParam("state", state)
.queryParam("login", "true") .queryParam("login", "true")
@ -223,8 +221,8 @@ public class ServletOAuthLogin {
if (!checkStateCookie()) return false; if (!checkStateCookie()) return false;
String client_id = realmInfo.getClientId(); String client_id = realmInfo.getMetadata().getResourceName();
String password = realmInfo.getCredentials().asMap().getFirst("password"); String password = realmInfo.getResourceCredentials().asMap().getFirst("password");
//String authHeader = BasicAuthHelper.createHeader(client_id, password); //String authHeader = BasicAuthHelper.createHeader(client_id, password);
String redirectUri = stripOauthParametersFromRedirect(); String redirectUri = stripOauthParametersFromRedirect();
Form form = new Form(); Form form = new Form();

View file

@ -26,6 +26,8 @@ public class ManagedResourceConfig {
protected String authUrl; protected String authUrl;
@JsonProperty("code-url") @JsonProperty("code-url")
protected String codeUrl; protected String codeUrl;
@JsonProperty("use-resource-role-mappings")
protected boolean useResourceRoleMappings;
@JsonProperty("ssl-not-required") @JsonProperty("ssl-not-required")
protected boolean sslNotRequired; protected boolean sslNotRequired;
@ -37,21 +39,27 @@ public class ManagedResourceConfig {
protected String truststore; protected String truststore;
@JsonProperty("truststore-password") @JsonProperty("truststore-password")
protected String truststorePassword; protected String truststorePassword;
@JsonProperty("client-id")
protected String clientId;
@JsonProperty("client-keystore") @JsonProperty("client-keystore")
protected String clientKeystore; protected String clientKeystore;
@JsonProperty("client-keystore-password") @JsonProperty("client-keystore-password")
protected String clientKeystorePassword; protected String clientKeystorePassword;
@JsonProperty("client-key-password") @JsonProperty("client-key-password")
protected String clientKeyPassword; protected String clientKeyPassword;
@JsonProperty("client-credentials") @JsonProperty("credentials")
protected Map<String, String> clientCredentials = new HashMap<String, String>(); protected Map<String, String> credentials = new HashMap<String, String>();
@JsonProperty("connection-pool-size") @JsonProperty("connection-pool-size")
protected int connectionPoolSize; protected int connectionPoolSize;
@JsonProperty("cancel-propagation") @JsonProperty("cancel-propagation")
protected boolean cancelPropagation; protected boolean cancelPropagation;
public boolean isUseResourceRoleMappings() {
return useResourceRoleMappings;
}
public void setUseResourceRoleMappings(boolean useResourceRoleMappings) {
this.useResourceRoleMappings = useResourceRoleMappings;
}
public boolean isSslNotRequired() { public boolean isSslNotRequired() {
return sslNotRequired; return sslNotRequired;
} }
@ -140,16 +148,8 @@ public class ManagedResourceConfig {
this.truststorePassword = truststorePassword; this.truststorePassword = truststorePassword;
} }
public String getClientId() { public Map<String, String> getCredentials() {
return clientId; return credentials;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public Map<String, String> getClientCredentials() {
return clientCredentials;
} }
public String getClientKeystore() { public String getClientKeystore() {

View file

@ -103,8 +103,9 @@ public class ManagedResourceConfigLoader {
} }
String realm = remoteSkeletonKeyConfig.getRealm(); String realm = remoteSkeletonKeyConfig.getRealm();
String resource = remoteSkeletonKeyConfig.getResource();
if (realm == null) throw new RuntimeException("Must set 'realm' in config"); if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String resource = remoteSkeletonKeyConfig.getResource();
if (resource == null) throw new RuntimeException("Must set 'resource' in config");
String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey(); String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
if (realmKeyPem == null) { if (realmKeyPem == null) {

View file

@ -9,6 +9,7 @@ import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.representations.idm.RequiredCredentialRepresentation; import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel; import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.resources.RealmsResource;
import org.picketlink.idm.credential.Credentials; import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.Password; import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.TOTPCredentials; import org.picketlink.idm.credential.TOTPCredentials;
@ -20,6 +21,8 @@ import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.NewCookie; import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -45,14 +48,19 @@ public class AuthenticationManager {
return realm.isRealmAdmin(user); return realm.isRealmAdmin(user);
} }
protected void expireIdentityCookie(Cookie cookie) { public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class); HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
if (response == null) return; if (response == null) {
NewCookie expireIt = new NewCookie(cookie.getName(), "", cookie.getPath(), null, "Expiring cookie", 0, false); logger.info("can't expire identity cookie, no HttpResponse");
return;
}
logger.info("Expiring identity cookie");
NewCookie expireIt = new NewCookie(TokenManager.KEYCLOAK_IDENTITY_COOKIE, "", uri.getPath(), null, "Expiring cookie", 0, false);
response.addNewCookie(expireIt); response.addNewCookie(expireIt);
} }
public User authenticateIdentityCookie(RealmModel realm, HttpHeaders headers) { public User authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
Cookie cookie = headers.getCookies().get(TokenManager.KEYCLOAK_IDENTITY_COOKIE); Cookie cookie = headers.getCookies().get(TokenManager.KEYCLOAK_IDENTITY_COOKIE);
if (cookie == null) return null; if (cookie == null) return null;
@ -61,19 +69,19 @@ public class AuthenticationManager {
SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId()); SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
if (!token.isActive()) { if (!token.isActive()) {
logger.info("identity cookie expired"); logger.info("identity cookie expired");
expireIdentityCookie(cookie); expireIdentityCookie(realm, uriInfo);
return null; return null;
} }
User user = realm.getIdm().getUser(token.getPrincipal()); User user = realm.getIdm().getUser(token.getPrincipal());
if (user == null || !user.isEnabled()) { if (user == null || !user.isEnabled()) {
logger.info("Unknown user in identity cookie"); logger.info("Unknown user in identity cookie");
expireIdentityCookie(cookie); expireIdentityCookie(realm, uriInfo);
return null; return null;
} }
return user; return user;
} catch (VerificationException e) { } catch (VerificationException e) {
logger.info("Failed to verify identity cookie", e); logger.info("Failed to verify identity cookie", e);
expireIdentityCookie(cookie); expireIdentityCookie(realm, uriInfo);
} }
return null; return null;
} }

View file

@ -1,17 +1,16 @@
package org.keycloak.services.managers; package org.keycloak.services.managers;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RequiredCredentialRepresentation; import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.representations.idm.ResourceRepresentation; import org.keycloak.representations.idm.ResourceRepresentation;
import org.keycloak.representations.idm.RoleMappingRepresentation; import org.keycloak.representations.idm.RoleMappingRepresentation;
import org.keycloak.representations.idm.ScopeMappingRepresentation; import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel; import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel; import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.UserCredentialModel; import org.keycloak.services.models.UserCredentialModel;
import org.keycloak.services.resources.RegistrationService;
import org.picketlink.idm.IdentityManager; import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.IdentitySession; import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Attribute; import org.picketlink.idm.model.Attribute;
@ -22,7 +21,6 @@ import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.SimpleUser; import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.security.KeyPair; import java.security.KeyPair;
@ -73,6 +71,7 @@ public class RealmManager {
SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID); SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
idm.add(agent); idm.add(agent);
RealmModel realm = new RealmModel(newRealm, identitySession); RealmModel realm = new RealmModel(newRealm, identitySession);
idm.add(new SimpleRole("*"));
return realm; return realm;
} }
@ -135,7 +134,7 @@ public class RealmManager {
} }
newRealm.getIdm().add(user); newRealm.getIdm().add(user);
if (userRep.getCredentials() != null) { if (userRep.getCredentials() != null) {
for (UserRepresentation.Credential cred : userRep.getCredentials()) { for (CredentialRepresentation cred : userRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel(); UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType()); credential.setType(cred.getType());
credential.setValue(cred.getValue()); credential.setValue(cred.getValue());
@ -145,25 +144,25 @@ public class RealmManager {
userMap.put(user.getLoginName(), user); userMap.put(user.getLoginName(), user);
} }
Map<String, Role> roles = new HashMap<String, Role>();
if (rep.getRoles() != null) { if (rep.getRoles() != null) {
for (String roleString : rep.getRoles()) { for (String roleString : rep.getRoles()) {
SimpleRole role = new SimpleRole(roleString.trim()); SimpleRole role = new SimpleRole(roleString.trim());
newRealm.getIdm().add(role); newRealm.getIdm().add(role);
roles.put(role.getName(), role);
} }
} }
if (rep.getResources() != null) {
createResources(rep, newRealm, userMap);
}
if (rep.getRoleMappings() != null) { if (rep.getRoleMappings() != null) {
for (RoleMappingRepresentation mapping : rep.getRoleMappings()) { for (RoleMappingRepresentation mapping : rep.getRoleMappings()) {
User user = userMap.get(mapping.getUsername()); User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) { for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim()); Role role = newRealm.getIdm().getRole(roleString.trim());
if (role == null) { if (role == null) {
role = new SimpleRole(roleString.trim()); role = new SimpleRole(roleString.trim());
newRealm.getIdm().add(role); newRealm.getIdm().add(role);
roles.put(role.getName(), role);
} }
newRealm.getIdm().grantRole(user, role); newRealm.getIdm().grantRole(user, role);
} }
@ -173,11 +172,10 @@ public class RealmManager {
if (rep.getScopeMappings() != null) { if (rep.getScopeMappings() != null) {
for (ScopeMappingRepresentation scope : rep.getScopeMappings()) { for (ScopeMappingRepresentation scope : rep.getScopeMappings()) {
for (String roleString : scope.getRoles()) { for (String roleString : scope.getRoles()) {
Role role = roles.get(roleString.trim()); Role role = newRealm.getIdm().getRole(roleString.trim());
if (role == null) { if (role == null) {
role = new SimpleRole(roleString.trim()); role = new SimpleRole(roleString.trim());
newRealm.getIdm().add(role); newRealm.getIdm().add(role);
roles.put(role.getName(), role);
} }
User user = userMap.get(scope.getUsername()); User user = userMap.get(scope.getUsername());
newRealm.addScope(user, role.getName()); newRealm.addScope(user, role.getName());
@ -185,43 +183,43 @@ public class RealmManager {
} }
} }
if (!roles.containsKey("*")) {
SimpleRole wildcard = new SimpleRole("*");
newRealm.getIdm().add(wildcard);
roles.put("*", wildcard);
}
if (rep.getResources() != null) {
createResources(rep, newRealm, userMap);
}
} }
protected void createResources(RealmRepresentation rep, RealmModel realm, Map<String, User> userMap) { protected void createResources(RealmRepresentation rep, RealmModel realm, Map<String, User> userMap) {
for (ResourceRepresentation resourceRep : rep.getResources()) { for (ResourceRepresentation resourceRep : rep.getResources()) {
ResourceModel resource = realm.addResource(resourceRep.getName()); ResourceModel resource = realm.addResource(resourceRep.getName());
resource.setManagementUrl(resourceRep.getAdminUrl());
resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired()); resource.setSurrogateAuthRequired(resourceRep.isSurrogateAuthRequired());
resource.updateResource(); resource.updateResource();
Map<String, Role> roles = new HashMap<String, Role>();
User resourceUser = resource.getResourceUser();
if (resourceRep.getCredentials() != null) {
for (CredentialRepresentation cred : resourceRep.getCredentials()) {
UserCredentialModel credential = new UserCredentialModel();
credential.setType(cred.getType());
credential.setValue(cred.getValue());
realm.updateCredential(resourceUser, credential);
}
}
userMap.put(resourceUser.getLoginName(), resourceUser);
if (resourceRep.getRoles() != null) { if (resourceRep.getRoles() != null) {
for (String roleString : resourceRep.getRoles()) { for (String roleString : resourceRep.getRoles()) {
SimpleRole role = new SimpleRole(roleString.trim()); SimpleRole role = new SimpleRole(roleString.trim());
resource.getIdm().add(role); resource.getIdm().add(role);
roles.put(role.getName(), role);
} }
} }
if (resourceRep.getRoleMappings() != null) { if (resourceRep.getRoleMappings() != null) {
for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) { for (RoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
User user = userMap.get(mapping.getUsername()); User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) { for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim()); Role role = resource.getIdm().getRole(roleString.trim());
if (role == null) { if (role == null) {
role = new SimpleRole(roleString.trim()); role = new SimpleRole(roleString.trim());
resource.getIdm().add(role); resource.getIdm().add(role);
roles.put(role.getName(), role);
} }
Role role1 = resource.getIdm().getRole(role.getName()); realm.getIdm().grantRole(user, role);
realm.getIdm().grantRole(user, role1);
} }
} }
} }
@ -229,22 +227,16 @@ public class RealmManager {
for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) { for (ScopeMappingRepresentation mapping : resourceRep.getScopeMappings()) {
User user = userMap.get(mapping.getUsername()); User user = userMap.get(mapping.getUsername());
for (String roleString : mapping.getRoles()) { for (String roleString : mapping.getRoles()) {
Role role = roles.get(roleString.trim()); Role role = resource.getIdm().getRole(roleString.trim());
if (role == null) { if (role == null) {
role = new SimpleRole(roleString.trim()); role = new SimpleRole(roleString.trim());
resource.getIdm().add(role); resource.getIdm().add(role);
roles.put(role.getName(), role);
} }
resource.addScope(user, role.getName()); resource.addScope(user, role.getName());
} }
} }
} }
if (!roles.containsKey("*")) { if (resourceRep.isUseRealmMappings()) realm.addScope(resource.getResourceUser(), "*");
SimpleRole wildcard = new SimpleRole("*");
resource.getIdm().add(wildcard);
roles.put("*", wildcard);
}
} }
} }
@ -266,7 +258,7 @@ public class RealmManager {
boolean hasBrowserCredentials = true; boolean hasBrowserCredentials = true;
for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) { for (RequiredCredentialRepresentation credential : rep.getRequiredCredentials()) {
boolean hasCredential = false; boolean hasCredential = false;
for (UserRepresentation.Credential cred : userRep.getCredentials()) { for (CredentialRepresentation cred : userRep.getCredentials()) {
if (cred.getType().equals(credential.getType())) { if (cred.getType().equals(credential.getType())) {
hasCredential = true; hasCredential = true;
break; break;

View file

@ -0,0 +1,47 @@
package org.keycloak.services.managers;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.TokenIdGenerator;
import org.keycloak.representations.idm.admin.LogoutAction;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.ResourceModel;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.Response;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class ResourceAdminManager {
public void logoutAll(RealmModel realm) {
singleLogOut(realm, null);
}
public void singleLogOut(RealmModel realm, String user) {
ResteasyClient client = new ResteasyClientBuilder()
.disableTrustManager() // todo fix this, should have a trust manager or a good default
.build();
List<ResourceModel> resources = realm.getResources();
for (ResourceModel resource : resources) {
logoutResource(realm, resource, user, client);
}
}
protected boolean logoutResource(RealmModel realm, ResourceModel resource, String user, ResteasyClient client) {
LogoutAction adminAction = new LogoutAction(TokenIdGenerator.generateId(), System.currentTimeMillis() / 1000 + 30, resource.getName(), user);
String token = new TokenManager().encodeToken(realm, adminAction);
Form form = new Form();
form.param("token", token);
Response response = client.target(resource.getManagementUrl()).queryParam("action", "logout").request().post(Entity.form(form));
boolean success = response.getStatus() == 204;
response.close();
return success;
}
}

View file

@ -3,15 +3,17 @@ 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.keycloak.services.resources.TokenService;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
import javax.ws.rs.ForbiddenException; import javax.ws.rs.ForbiddenException;
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.Response;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
@ -38,6 +40,7 @@ public class TokenManager {
accessCodeMap.clear(); accessCodeMap.clear();
} }
public AccessCodeEntry pullAccessCode(String key) { public AccessCodeEntry pullAccessCode(String key) {
return accessCodeMap.remove(key); return accessCodeMap.remove(key);
} }
@ -55,7 +58,7 @@ public class TokenManager {
{ {
SkeletonKeyToken token = null; SkeletonKeyToken token = null;
if (scopeParam != null) token = createScopedToken(scopeParam, realm, client, user); if (scopeParam != null) token = createScopedToken(scopeParam, realm, client, user);
else token = createLoginToken(realm, client, user); else token = createUnscopedToken(realm, client, user);
AccessCodeEntry code = new AccessCodeEntry(); AccessCodeEntry code = new AccessCodeEntry();
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan()); code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
@ -72,15 +75,7 @@ public class TokenManager {
} }
public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) { public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = initToken(realm, client, user);
token.id(RealmManager.generateId());
token.principal(user.getLoginName());
token.audience(realm.getName());
token.issuedNow();
token.issuedFor(client.getLoginName());
if (realm.getTokenLifespan() > 0) {
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
}
Map<String, ResourceModel> resourceMap = realm.getResourceMap(); Map<String, ResourceModel> resourceMap = realm.getResourceMap();
for (String res : scope.keySet()) { for (String res : scope.keySet()) {
@ -102,23 +97,53 @@ public class TokenManager {
return token; return token;
} }
protected SkeletonKeyToken initToken(RealmModel realm, User client, User user) {
SkeletonKeyToken token = new SkeletonKeyToken();
token.id(RealmManager.generateId());
token.principal(user.getLoginName());
token.audience(realm.getName());
token.issuedNow();
token.issuedFor(client.getLoginName());
if (realm.getTokenLifespan() > 0) {
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
}
return token;
}
public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) { public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) {
SkeletonKeyScope scope = decodeScope(scopeParam); SkeletonKeyScope scope = decodeScope(scopeParam);
return createScopedToken(scope, realm, client, user); return createScopedToken(scope, realm, client, user);
} }
public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user) { public SkeletonKeyToken createUnscopedToken(RealmModel realm, User client, User user) {
Set<String> mapping = realm.getScopes(client);
if (!mapping.contains("*")) { SkeletonKeyToken token = initToken(realm, client, user);
throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
Set<String> realmMapping = realm.getRoleMappings(user);
if (realmMapping != null && realmMapping.size() > 0) {
Set<String> scope = realm.getScope(client);
SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
for (String role : realmMapping) {
if (scope.contains("*") || scope.contains(role)) access.addRole(role);
}
token.setRealmAccess(access);
}
List<ResourceModel> resources = realm.getResources();
for (ResourceModel resource : resources) {
Set<String> scope = resource.getScope(client);
Set<String> mapping = resource.getRoleMappings(user);
if (mapping.size() == 0 || scope.size() == 0) continue;
SkeletonKeyToken.Access access = token.addAccess(resource.getName())
.verifyCaller(resource.isSurrogateAuthRequired());
for (String role : mapping) {
if (scope.contains("*") || scope.contains(role)) access.addRole(role);
}
} }
SkeletonKeyToken token = createAccessToken(realm, user);
token.issuedFor(client.getLoginName());
return token; return token;
} }
public String encodeScope(SkeletonKeyScope scope) { public String encodeScope(SkeletonKeyScope scope) {
String token = null; String token = null;
try { try {
@ -187,7 +212,7 @@ public class TokenManager {
return token; return token;
} }
public String encodeToken(RealmModel realm, SkeletonKeyToken token) { public String encodeToken(RealmModel realm, Object token) {
byte[] tokenBytes = null; byte[] tokenBytes = null;
try { try {
tokenBytes = JsonSerialization.toByteArray(token, false); tokenBytes = JsonSerialization.toByteArray(token, false);

View file

@ -18,6 +18,8 @@ import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant; import org.picketlink.idm.model.Grant;
import org.picketlink.idm.model.Realm; import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role; import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.Tier; import org.picketlink.idm.model.Tier;
import org.picketlink.idm.model.User; import org.picketlink.idm.model.User;
import org.picketlink.idm.query.IdentityQuery; import org.picketlink.idm.query.IdentityQuery;
@ -293,8 +295,15 @@ public class RealmModel {
relationship.setResourceName(name); relationship.setResourceName(name);
relationship.setRealmAgent(realmAgent); relationship.setRealmAgent(realmAgent);
relationship.setResourceId(newTier.getId()); relationship.setResourceId(newTier.getId());
relationship.setManagementUrl(""); // Picketlink doesn't like null attribute values
User resourceUser = new SimpleUser(name);
idm.add(resourceUser);
relationship.setResourceUser(resourceUser);
idm.add(relationship); idm.add(relationship);
return new ResourceModel(newTier, relationship, this, identitySession); ResourceModel resource = new ResourceModel(newTier, relationship, this, identitySession);
resource.getIdm().add(new SimpleRole("*"));
resource.addScope(resourceUser, "*");
return resource;
} }
public Set<String> getRoleMappings(User user) { public Set<String> getRoleMappings(User user) {
@ -320,7 +329,7 @@ public class RealmModel {
} }
public Set<String> getScopes(Agent agent) { public Set<String> getScope(Agent agent) {
RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class); RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
query.setParameter(ScopeRelationship.CLIENT, agent); query.setParameter(ScopeRelationship.CLIENT, agent);
List<ScopeRelationship> scope = query.getResultList(); List<ScopeRelationship> scope = query.getResultList();

View file

@ -41,6 +41,10 @@ public class ResourceModel {
getIdm().update(agent); getIdm().update(agent);
} }
public User getResourceUser() {
return agent.getResourceUser();
}
public String getId() { public String getId() {
return tier.getId(); return tier.getId();
} }
@ -69,6 +73,14 @@ public class ResourceModel {
agent.setSurrogateAuthRequired(surrogateAuthRequired); agent.setSurrogateAuthRequired(surrogateAuthRequired);
} }
public String getManagementUrl() {
return agent.getManagementUrl();
}
public void setManagementUrl(String url) {
agent.setManagementUrl(url);
}
public List<Role> getRoles() { public List<Role> getRoles() {
IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class); IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
query.setParameter(Role.PARTITION, tier); query.setParameter(Role.PARTITION, tier);
@ -90,10 +102,14 @@ public class ResourceModel {
IdentityManager idm = getIdm(); IdentityManager idm = getIdm();
Role role = idm.getRole(roleName); Role role = idm.getRole(roleName);
if (role == null) throw new RuntimeException("role not found"); if (role == null) throw new RuntimeException("role not found");
addScope(agent, role);
}
public void addScope(Agent agent, Role role) {
ScopeRelationship scope = new ScopeRelationship(); ScopeRelationship scope = new ScopeRelationship();
scope.setClient(agent); scope.setClient(agent);
scope.setScope(role); scope.setScope(role);
} }
public Set<String> getScope(Agent agent) { public Set<String> getScope(Agent agent) {

View file

@ -3,6 +3,7 @@ package org.keycloak.services.models.relationships;
import org.picketlink.idm.model.AbstractAttributedType; import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent; import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Relationship; import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.User;
import org.picketlink.idm.model.annotation.AttributeProperty; import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.annotation.IdentityProperty; import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.query.RelationshipQueryParameter; import org.picketlink.idm.query.RelationshipQueryParameter;
@ -23,8 +24,10 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
}; };
protected Agent realmAgent; protected Agent realmAgent;
protected User resourceUser;
protected String resourceId; protected String resourceId;
protected String resourceName; protected String resourceName;
protected String managementUrl = ""; // Picketlink doesn't like null attribute values
protected boolean surrogateAuthRequired; protected boolean surrogateAuthRequired;
protected boolean enabled; protected boolean enabled;
@ -37,6 +40,15 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
this.realmAgent = realmAgent; this.realmAgent = realmAgent;
} }
@IdentityProperty
public User getResourceUser() {
return resourceUser;
}
public void setResourceUser(User resourceUser) {
this.resourceUser = resourceUser;
}
@AttributeProperty @AttributeProperty
public String getResourceId() { public String getResourceId() {
return resourceId; return resourceId;
@ -72,4 +84,15 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
@AttributeProperty
public String getManagementUrl()
{
return managementUrl;
}
public void setManagementUrl(String managementUrl) {
if (managementUrl == null) managementUrl = ""; // Picketlink doesn't like NULL attribute values.
this.managementUrl = managementUrl;
}
} }

View file

@ -52,9 +52,9 @@ public class RealmSubResource {
StringBuffer html = new StringBuffer(); StringBuffer html = new StringBuffer();
String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString(); String authUri = TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString();
String codeUri = TokenService.accessCodeRequest(uriInfo).build(realm.getId()).toString(); String codeUri = TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString();
String grantUrl = TokenService.grantRequest(uriInfo).build(realm.getId()).toString(); String grantUrl = TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString();
String idGrantUrl = TokenService.identityGrantRequest(uriInfo).build(realm.getId()).toString(); String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString();
html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>"); html.append("<html><body><h1>Realm: ").append(realm.getName()).append("</h1>");
html.append("<p>auth: ").append(authUri).append("</p>"); html.append("<p>auth: ").append(authUri).append("</p>");
@ -76,9 +76,9 @@ public class RealmSubResource {
rep.setAdminRole(ADMIN_ROLE); rep.setAdminRole(ADMIN_ROLE);
rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString()); rep.setAuthorizationUrl(TokenService.loginPageUrl(uriInfo).build(realm.getId()).toString());
rep.setCodeUrl(TokenService.accessCodeRequest(uriInfo).build(realm.getId()).toString()); rep.setCodeUrl(TokenService.accessCodeToTokenUrl(uriInfo).build(realm.getId()).toString());
rep.setGrantUrl(TokenService.grantRequest(uriInfo).build(realm.getId()).toString()); rep.setGrantUrl(TokenService.grantAccessTokenUrl(uriInfo).build(realm.getId()).toString());
String idGrantUrl = TokenService.identityGrantRequest(uriInfo).build(realm.getId()).toString(); String idGrantUrl = TokenService.grantIdentityTokenUrl(uriInfo).build(realm.getId()).toString();
rep.setIdentityGrantUrl(idGrantUrl); rep.setIdentityGrantUrl(idGrantUrl);
return rep; return rep;
} }

View file

@ -1,6 +1,7 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.RealmModel; import org.keycloak.services.models.RealmModel;
@ -12,10 +13,8 @@ import org.picketlink.idm.model.User;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.ForbiddenException; import javax.ws.rs.ForbiddenException;
import javax.ws.rs.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -57,7 +56,7 @@ public class RegistrationService {
user = new SimpleUser(newUser.getUsername()); user = new SimpleUser(newUser.getUsername());
defaultRealm.getIdm().add(user); defaultRealm.getIdm().add(user);
for (UserRepresentation.Credential cred : newUser.getCredentials()) { for (CredentialRepresentation cred : newUser.getCredentials()) {
UserCredentialModel credModel = new UserCredentialModel(); UserCredentialModel credModel = new UserCredentialModel();
credModel.setType(cred.getType()); credModel.setType(cred.getType());
credModel.setValue(cred.getValue()); credModel.setValue(cred.getValue());

View file

@ -13,6 +13,7 @@ import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.JspRequestParameters; import org.keycloak.services.JspRequestParameters;
import org.keycloak.services.managers.AccessCodeEntry; import org.keycloak.services.managers.AccessCodeEntry;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
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.RequiredCredentialModel;
@ -31,7 +32,6 @@ import javax.ws.rs.core.Context;
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.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;
@ -51,7 +51,6 @@ public class TokenService {
protected static final Logger logger = Logger.getLogger(TokenService.class); protected static final Logger logger = Logger.getLogger(TokenService.class);
//protected Map<String, AccessCodeEntry> accessCodeMap;
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
@ -73,39 +72,40 @@ public class TokenService {
protected RealmModel realm; protected RealmModel realm;
protected TokenManager tokenManager; protected TokenManager tokenManager;
protected AuthenticationManager authManager = new AuthenticationManager(); protected AuthenticationManager authManager = new AuthenticationManager();
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
public TokenService(RealmModel realm, TokenManager tokenManager) { public TokenService(RealmModel realm, TokenManager tokenManager) {
this.realm = realm; this.realm = realm;
this.tokenManager = tokenManager; this.tokenManager = tokenManager;
} }
public static UriBuilder tokenServiceBase(UriInfo uriInfo) { public static UriBuilder tokenServiceBaseUrl(UriInfo uriInfo) {
UriBuilder base = uriInfo.getBaseUriBuilder() UriBuilder base = uriInfo.getBaseUriBuilder()
.path(RealmsResource.class).path(RealmsResource.class, "getTokenService"); .path(RealmsResource.class).path(RealmsResource.class, "getTokenService");
return base; return base;
} }
public static UriBuilder accessCodeRequest(UriInfo uriInfo) { public static UriBuilder accessCodeToTokenUrl(UriInfo uriInfo) {
return tokenServiceBase(uriInfo).path(TokenService.class, "accessRequest"); return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "accessCodeToToken");
} }
public static UriBuilder grantRequest(UriInfo uriInfo) { public static UriBuilder grantAccessTokenUrl(UriInfo uriInfo) {
return tokenServiceBase(uriInfo).path(TokenService.class, "accessTokenGrant"); return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "grantAccessToken");
} }
public static UriBuilder identityGrantRequest(UriInfo uriInfo) { public static UriBuilder grantIdentityTokenUrl(UriInfo uriInfo) {
return tokenServiceBase(uriInfo).path(TokenService.class, "accessTokenGrant"); return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "grantIdentityToken");
} }
public static UriBuilder loginPageUrl(UriInfo uriInfo) { public static UriBuilder loginPageUrl(UriInfo uriInfo) {
return tokenServiceBase(uriInfo).path(TokenService.class, "loginRequest"); return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "loginPage");
} }
public static UriBuilder logainActionUrl(UriInfo uriInfo) { public static UriBuilder processLoginUrl(UriInfo uriInfo) {
return tokenServiceBase(uriInfo).path(TokenService.class, "login"); return tokenServiceBaseUrl(uriInfo).path(TokenService.class, "processLogin");
} }
@ -113,7 +113,7 @@ public class TokenService {
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response identityTokenGrant(MultivaluedMap<String, String> form) { public Response grantIdentityToken(MultivaluedMap<String, String> form) {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) { if (username == null) {
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
@ -142,7 +142,7 @@ public class TokenService {
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response accessTokenGrant(MultivaluedMap<String, String> form) { public Response grantAccessToken(MultivaluedMap<String, String> form) {
String username = form.getFirst(AuthenticationManager.FORM_USERNAME); String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
if (username == null) { if (username == null) {
throw new NotAuthorizedException("No user"); throw new NotAuthorizedException("No user");
@ -169,7 +169,7 @@ public class TokenService {
@Path("auth/request/login") @Path("auth/request/login")
@POST @POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response login(MultivaluedMap<String, String> formData) { public Response processLogin(MultivaluedMap<String, String> formData) {
String clientId = formData.getFirst("client_id"); String clientId = formData.getFirst("client_id");
String scopeParam = formData.getFirst("scope"); String scopeParam = formData.getFirst("scope");
String state = formData.getFirst("state"); String state = formData.getFirst("state");
@ -226,7 +226,7 @@ public class TokenService {
@Path("access/codes") @Path("access/codes")
@POST @POST
@Produces("application/json") @Produces("application/json")
public Response accessRequest(MultivaluedMap<String, String> formData) { public Response accessCodeToToken(MultivaluedMap<String, String> formData) {
logger.info("accessRequest <---"); logger.info("accessRequest <---");
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
throw new NotAuthorizedException("Realm not enabled"); throw new NotAuthorizedException("Realm not enabled");
@ -356,7 +356,7 @@ public class TokenService {
String scopeParam, String scopeParam,
String state) { String state) {
request.setAttribute(RealmModel.class.getName(), realm); request.setAttribute(RealmModel.class.getName(), realm);
request.setAttribute("KEYCLOAK_LOGIN_ACTION", logainActionUrl(uriInfo).build(realm.getId())); request.setAttribute("KEYCLOAK_LOGIN_ACTION", processLoginUrl(uriInfo).build(realm.getId()));
// RESTEASY eats the form data, so we send via an attribute // RESTEASY eats the form data, so we send via an attribute
request.setAttribute("redirect_uri", redirect); request.setAttribute("redirect_uri", redirect);
@ -369,11 +369,11 @@ public class TokenService {
@Path("login") @Path("login")
@GET @GET
public Response loginRequest(@QueryParam("response_type") String responseType, public Response loginPage(@QueryParam("response_type") String responseType,
@QueryParam("redirect_uri") String redirect, @QueryParam("redirect_uri") String redirect,
@QueryParam("client_id") String clientId, @QueryParam("client_id") String clientId,
@QueryParam("scope") String scopeParam, @QueryParam("scope") String scopeParam,
@QueryParam("state") String state) { @QueryParam("state") String state) {
if (!realm.isEnabled()) { if (!realm.isEnabled()) {
securityFailureForward("Realm not enabled"); securityFailureForward("Realm not enabled");
return null; return null;
@ -390,7 +390,7 @@ public class TokenService {
return null; return null;
} }
User user = authManager.authenticateIdentityCookie(realm, headers); User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) { if (user != null) {
return redirectAccessCode(scopeParam, state, redirect, client, user); return redirectAccessCode(scopeParam, state, redirect, client, user);
} }
@ -400,6 +400,21 @@ public class TokenService {
return null; return null;
} }
@Path("logout")
@GET
public Response logout(@QueryParam("redirect_uri") String redirectUri) {
// todo do we care if anybody can trigger this?
User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) {
logger.info("Logging out: " + user.getLoginName());
authManager.expireIdentityCookie(realm, uriInfo);
resourceAdminManager.singleLogOut(realm, user.getLoginName());
}
// todo manage legal redirects
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) { private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
StringBuffer html = new StringBuffer(); StringBuffer html = new StringBuffer();
if (scopeParam != null) { if (scopeParam != null) {
@ -431,7 +446,7 @@ public class TokenService {
} }
html.append("</table><p>To Authorize, please login below</p>"); html.append("</table><p>To Authorize, please login below</p>");
} else { } else {
Set<String> scopeMapping = realm.getScopes(client); Set<String> scopeMapping = realm.getScope(client);
if (scopeMapping.contains("*")) { if (scopeMapping.contains("*")) {
html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>"); html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
if (validationError != null) { if (validationError != null) {
@ -485,7 +500,7 @@ public class TokenService {
} }
} }
UriBuilder formActionUri = logainActionUrl(uriInfo); UriBuilder formActionUri = processLoginUrl(uriInfo);
String action = formActionUri.build(realm.getId()).toString(); String action = formActionUri.build(realm.getId()).toString();
html.append("<form action=\"").append(action).append("\" method=\"POST\">"); html.append("<form action=\"").append(action).append("\" method=\"POST\">");
html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>"); html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");

View file

@ -166,7 +166,7 @@ public class AdapterTest {
idm.add(new SimpleRole("admin")); idm.add(new SimpleRole("admin"));
idm.add(new SimpleRole("user")); idm.add(new SimpleRole("user"));
List<Role> roles = realmModel.getRoles(); List<Role> roles = realmModel.getRoles();
Assert.assertEquals(2, roles.size()); Assert.assertEquals(3, roles.size());
SimpleUser user = new SimpleUser("bburke"); SimpleUser user = new SimpleUser("bburke");
idm.add(user); idm.add(user);
Role role = idm.getRole("user"); Role role = idm.getRole("user");

View file

@ -104,7 +104,7 @@ public class ImportTest {
User user = realm.getIdm().getUser("loginclient"); User user = realm.getIdm().getUser("loginclient");
Assert.assertNotNull(user); Assert.assertNotNull(user);
Set<String> scopes = realm.getScopes(user); Set<String> scopes = realm.getScope(user);
System.out.println("Scopes size: " + scopes.size()); System.out.println("Scopes size: " + scopes.size());
Assert.assertTrue(scopes.contains("*")); Assert.assertTrue(scopes.contains("*"));