keycloak-uncached
Changes
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java 2(+1 -1)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java 5(+3 -2)
services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceEntity.java 10(+5 -5)
services/src/main/java/org/keycloak/services/models/picketlink/PicketlinkKeycloakSession.java 15(+13 -2)
services/src/main/java/org/keycloak/services/models/picketlink/relationships/RequiredCredentialRelationship.java 2(+0 -2)
Details
diff --git a/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java b/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
index 1d81d72..eab7b1e 100755
--- a/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
+++ b/examples/as7-eap-demo/server/src/main/java/org/keycloak/example/demo/DemoApplication.java
@@ -7,7 +7,8 @@ import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.resources.KeycloakApplication;
-import org.keycloak.services.resources.RegistrationService;
+import org.keycloak.services.resources.SaasService;
+import org.keycloak.services.resources.SaasService;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -35,12 +36,12 @@ public class DemoApplication extends KeycloakApplication {
defaultRealm.setEnabled(true);
defaultRealm.setTokenLifespan(300);
defaultRealm.setAccessCodeLifespan(60);
- defaultRealm.setSslNotRequired(false);
+ defaultRealm.setSslNotRequired(true);
defaultRealm.setCookieLoginAllowed(true);
defaultRealm.setRegistrationAllowed(true);
manager.generateRealmKeys(defaultRealm);
defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
- defaultRealm.addRole(RegistrationService.REALM_CREATOR_ROLE);
+ defaultRealm.addRole(SaasService.REALM_CREATOR_ROLE);
RealmRepresentation rep = loadJson("META-INF/testrealm.json");
RealmModel realm = manager.createRealm("demo", rep.getRealm());
diff --git a/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp b/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
index f0f42ba..9a33002 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
+++ b/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
@@ -61,11 +61,11 @@
<hr/>
<% String errorMessage = (String)request.getAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE");
if (errorMessage != null) { %>
- <div id="error-message" class="alert alert-block alert-error" style="block"><%=errorMessage%></div>
+ <div id="error-message" class="alert alert-block alert-error" ><%=errorMessage%></div>
<% } %>
<form class="form-horizontal" name="loginForm" action="<%=request.getAttribute("KEYCLOAK_LOGIN_ACTION")%>" method="POST">
<div class="control-group">
- <label class="control-label" for="username">User Name</label>
+ <label class="control-label">User Name</label>
<div class="controls">
<% if (username != null) { %>
@@ -123,5 +123,6 @@
</div>
<footer>
<p>Powered By Keycloak</p>
+</footer>
</body>
</html>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
index 3614d58..3a49660 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
@@ -163,7 +163,7 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
protected void remoteLogout(JWSInput token, HttpServletResponse response) throws IOException {
try {
- log.debug("->> remoteLogout: ");
+ log.info("->> remoteLogout: ");
LogoutAction action = JsonSerialization.fromBytes(LogoutAction.class, token.getContent());
if (action.isExpired()) {
log.warn("admin request failed, expired token");
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
index b3cdebb..f046eed 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
@@ -175,8 +175,9 @@ public class ServletOAuthLogin {
return false;
}
// reset the cookie
- Cookie reset = new Cookie(stateCookie.getName(), stateCookie.getValue());
- reset.setPath(stateCookie.getPath());
+ log.info("** reseting application state cookie");
+ Cookie reset = new Cookie(realmInfo.getStateCookieName(), "");
+ reset.setPath(getDefaultCookiePath());
reset.setMaxAge(0);
response.addCookie(reset);
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 8bcf3c6..e98cdbc 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -1,5 +1,7 @@
package org.keycloak.services.managers;
+import org.jboss.resteasy.jose.jws.JWSBuilder;
+import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
@@ -11,6 +13,7 @@ import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.services.resources.SaasService;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.core.Cookie;
@@ -31,6 +34,7 @@ import java.util.Set;
public class AuthenticationManager {
protected Logger logger = Logger.getLogger(AuthenticationManager.class);
public static final String FORM_USERNAME = "username";
+ public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY";
/**
* Grabs token from headers, authenticates, authorizes
@@ -44,21 +48,99 @@ public class AuthenticationManager {
return realm.isRealmAdmin(user);
}
+ public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) {
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(RealmManager.generateId());
+ token.issuedNow();
+ token.principal(username);
+ token.audience(realm.getId());
+ if (realm.getTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ }
+ return token;
+ }
+
+
+ public NewCookie createLoginCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
+ String cookieName = KEYCLOAK_IDENTITY_COOKIE;
+ URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
+ String cookiePath = uri.getPath();
+ return createLoginCookie(realm, user, cookieName, cookiePath);
+ }
+
+ public NewCookie createSaasIdentityCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
+ String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
+ URI uri = SaasService.saasCookiePath(uriInfo).build();
+ String cookiePath = uri.getPath();
+ return createLoginCookie(realm, user, cookieName, cookiePath);
+ }
+
+
+ protected NewCookie createLoginCookie(RealmModel realm, UserModel user, String cookieName, String cookiePath) {
+ SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
+ String encoded = encodeToken(realm, identityToken);
+ boolean secureOnly = !realm.isSslNotRequired();
+ logger.info("creatingLoginCookie - name: " + cookieName + " path: " + cookiePath);
+ NewCookie cookie = new NewCookie(cookieName, encoded, cookiePath, null, null, NewCookie.DEFAULT_MAX_AGE, secureOnly, false);
+ return cookie;
+ }
+
+ protected String encodeToken(RealmModel realm, Object token) {
+ byte[] tokenBytes = null;
+ try {
+ tokenBytes = JsonSerialization.toByteArray(token, false);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ String encodedToken = new JWSBuilder()
+ .content(tokenBytes)
+ .rsa256(realm.getPrivateKey());
+ return encodedToken;
+ }
+
+
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
+ logger.info("Expiring identity cookie");
+ String path = uri.getPath();
+ String cookieName = KEYCLOAK_IDENTITY_COOKIE;
+ expireCookie(cookieName, path);
+ }
+
+ public void expireSaasIdentityCookie(UriInfo uriInfo) {
+ URI uri = SaasService.saasCookiePath(uriInfo).build();
+ String cookiePath = uri.getPath();
+ expireCookie(SaasService.SAAS_IDENTITY_COOKIE, cookiePath);
+ }
+
+ protected void expireCookie(String cookieName, String path) {
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
if (response == null) {
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);
+ logger.info("Expiring cookie: " + cookieName + " path: " + path);
+ NewCookie expireIt = new NewCookie(cookieName, "", path, null, "Expiring cookie", 0, false);
response.addNewCookie(expireIt);
}
public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
- Cookie cookie = headers.getCookies().get(TokenManager.KEYCLOAK_IDENTITY_COOKIE);
- if (cookie == null) return null;
+ String cookieName = KEYCLOAK_IDENTITY_COOKIE;
+ return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+ }
+
+ public UserModel authenticateSaasIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
+ String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
+ return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+ }
+
+
+ protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
+ Cookie cookie = headers.getCookies().get(cookieName);
+ if (cookie == null) {
+ logger.info("authenticateCookie could not find cookie: " + cookieName);
+ return null;
+ }
String tokenString = cookie.getValue();
try {
@@ -112,7 +194,6 @@ public class AuthenticationManager {
}
public boolean authenticateForm(RealmModel realm, UserModel user, MultivaluedMap<String, String> formData) {
- String username = user.getLoginName();
Set<String> types = new HashSet<String>();
for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
diff --git a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
index fd2fe2a..0f1760c 100755
--- a/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ResourceAdminManager.java
@@ -2,6 +2,7 @@ package org.keycloak.services.managers;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.logging.Logger;
import org.keycloak.TokenIdGenerator;
import org.keycloak.representations.idm.admin.LogoutAction;
import org.keycloak.services.models.RealmModel;
@@ -17,6 +18,7 @@ import java.util.List;
* @version $Revision: 1 $
*/
public class ResourceAdminManager {
+ protected Logger logger = Logger.getLogger(ResourceAdminManager.class);
public void logoutAll(RealmModel realm) {
singleLogOut(realm, null);
@@ -28,6 +30,7 @@ public class ResourceAdminManager {
.build();
List<ResourceModel> resources = realm.getResources();
+ logger.info("logging out " + resources.size() + " resoures.");
for (ResourceModel resource : resources) {
logoutResource(realm, resource, user, client);
}
@@ -38,7 +41,9 @@ public class ResourceAdminManager {
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));
+ String managementUrl = resource.getManagementUrl();
+ logger.info("logout user: " + user + " resource: " + resource.getName() + " url" + managementUrl);
+ Response response = client.target(managementUrl).queryParam("action", "logout").request().post(Entity.form(form));
boolean success = response.getStatus() == 204;
response.close();
return success;
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 4f9bdb3..121de14 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class TokenManager {
- public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY";
protected Map<String, AccessCodeEntry> accessCodeMap = new ConcurrentHashMap<String, AccessCodeEntry>();
public void clearAccessCodes() {
@@ -45,14 +44,6 @@ public class TokenManager {
return accessCodeMap.remove(key);
}
- public NewCookie createLoginCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
- SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
- String encoded = encodeToken(realm, identityToken);
- URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
- boolean secureOnly = !realm.isSslNotRequired();
- NewCookie cookie = new NewCookie(KEYCLOAK_IDENTITY_COOKIE, encoded, uri.getPath(), null, null, NewCookie.DEFAULT_MAX_AGE, secureOnly, true);
- return cookie;
- }
public AccessCodeEntry createAccessCode(String scopeParam, String state, String redirect, RealmModel realm, UserModel client, UserModel user) {
AccessCodeEntry code = new AccessCodeEntry();
@@ -212,17 +203,6 @@ public class TokenManager {
return token;
}
- public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) {
- SkeletonKeyToken token = new SkeletonKeyToken();
- token.id(RealmManager.generateId());
- token.issuedNow();
- token.principal(username);
- token.audience(realm.getId());
- if (realm.getTokenLifespan() > 0) {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
- }
- return token;
- }
public String encodeToken(RealmModel realm, Object token) {
byte[] tokenBytes = null;
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceData.java b/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceData.java
index 7133039..2a02572 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceData.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceData.java
@@ -23,6 +23,7 @@ public class ResourceData extends AbstractPartition {
super(name);
}
+ @AttributeProperty
public String getResourceName() {
return resourceName;
}
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceEntity.java b/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceEntity.java
index c64c33c..a2d43f8 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceEntity.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/mappings/ResourceEntity.java
@@ -24,7 +24,7 @@ public class ResourceEntity implements Serializable {
private PartitionTypeEntity partitionTypeEntity;
@AttributeValue
- private String realmName;
+ private String resourceName;
@AttributeValue
private boolean enabled;
@AttributeValue
@@ -45,12 +45,12 @@ public class ResourceEntity implements Serializable {
this.partitionTypeEntity = partitionTypeEntity;
}
- public String getRealmName() {
- return realmName;
+ public String getResourceName() {
+ return resourceName;
}
- public void setRealmName(String realmName) {
- this.realmName = realmName;
+ public void setResourceName(String realmName) {
+ this.resourceName = realmName;
}
public boolean isEnabled() {
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/PicketlinkKeycloakSession.java b/services/src/main/java/org/keycloak/services/models/picketlink/PicketlinkKeycloakSession.java
index 8efe790..b6becf9 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/PicketlinkKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/PicketlinkKeycloakSession.java
@@ -1,6 +1,8 @@
package org.keycloak.services.models.picketlink;
+import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.NotImplementedYetException;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakTransaction;
import org.keycloak.services.models.RealmModel;
@@ -17,6 +19,7 @@ import java.util.concurrent.atomic.AtomicLong;
public class PicketlinkKeycloakSession implements KeycloakSession {
public static ThreadLocal<EntityManager> currentEntityManager = new ThreadLocal<EntityManager>();
public static ThreadLocal<Exception> setWhere = new ThreadLocal<Exception>();
+ public static ThreadLocal<String> setFromPath = new ThreadLocal<String>();
protected PartitionManager partitionManager;
protected EntityManager entityManager;
@@ -31,7 +34,14 @@ public class PicketlinkKeycloakSession implements KeycloakSession {
if (currentEntityManager.get() != null)
{
setWhere.get().printStackTrace();
- throw new IllegalStateException("Thread local was leaked!");
+ String path = setFromPath.get();
+ if (path == null) path = "???";
+
+ throw new IllegalStateException("Thread local was leaked! from path: " + path);
+ }
+ HttpRequest request = ResteasyProviderFactory.getContextData(HttpRequest.class);
+ if (request != null) {
+ setFromPath.set(request.getUri().getPath());
}
currentEntityManager.set(entityManager);
setWhere.set(new Exception());
@@ -75,9 +85,10 @@ public class PicketlinkKeycloakSession implements KeycloakSession {
@Override
public void close() {
- if (entityManager.getTransaction().isActive()) entityManager.getTransaction().rollback();
+ setFromPath.set(null);
setWhere.set(null);
currentEntityManager.set(null);
+ if (entityManager.getTransaction().isActive()) entityManager.getTransaction().rollback();
if (entityManager.isOpen()) entityManager.close();
}
}
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java
index b0ad70b..7bff8af 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/RealmAdapter.java
@@ -390,11 +390,17 @@ public class RealmAdapter implements RealmModel {
@Override
public ResourceModel addResource(String name) {
- ResourceData resourceData = new ResourceData(name);
+ ResourceData resourceData = new ResourceData(RealmManager.generateId());
User resourceUser = new User(name);
idm.add(resourceUser);
resourceData.setResourceUser(resourceUser);
+ resourceData.setResourceName(name);
+ resourceData.setResourceUser(resourceUser);
partitionManager.add(resourceData);
+ ResourceRelationship resourceRelationship = new ResourceRelationship();
+ resourceRelationship.setRealm(realm.getName());
+ resourceRelationship.setResource(resourceData.getName());
+ getRelationshipManager().add(resourceRelationship);
ResourceModel resource = new ResourceAdapter(resourceData, this, partitionManager);
resource.addRole("*");
resource.addScope(new UserAdapter(resourceUser, idm), "*");
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/RequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/RequiredCredentialRelationship.java
index 1af2627..4434a19 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/RequiredCredentialRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/RequiredCredentialRelationship.java
@@ -1,12 +1,10 @@
package org.keycloak.services.models.picketlink.relationships;
-import org.keycloak.services.models.picketlink.mappings.RealmData;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.query.AttributeParameter;
-import org.picketlink.idm.query.RelationshipQueryParameter;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java
index d826a4e..429ea25 100755
--- a/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/picketlink/relationships/ResourceRelationship.java
@@ -1,15 +1,10 @@
package org.keycloak.services.models.picketlink.relationships;
-import org.keycloak.services.models.picketlink.mappings.RealmData;
-import org.keycloak.services.models.picketlink.mappings.ResourceData;
import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Relationship;
import org.picketlink.idm.model.annotation.AttributeProperty;
-import org.picketlink.idm.model.sample.Agent;
-import org.picketlink.idm.model.sample.User;
import org.picketlink.idm.query.AttributeParameter;
-import org.picketlink.idm.query.RelationshipQueryParameter;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -20,9 +15,10 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
public static final AttributeParameter REALM = new AttributeParameter("realm");
- protected String realm;
- protected String resource;
+ public ResourceRelationship() {
+ }
+ @AttributeProperty
public String getRealm() {
return (String)getAttribute("realm").getValue();
}
@@ -32,6 +28,7 @@ public class ResourceRelationship extends AbstractAttributedType implements Rela
}
+ @AttributeProperty
public String getResource() {
return (String)getAttribute("resource").getValue();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/AbstractLoginService.java b/services/src/main/java/org/keycloak/services/resources/AbstractLoginService.java
old mode 100644
new mode 100755
index b2103c6..1814ab3
--- a/services/src/main/java/org/keycloak/services/resources/AbstractLoginService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AbstractLoginService.java
@@ -11,6 +11,7 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.services.JspRequestParameters;
import org.keycloak.services.managers.AccessCodeEntry;
+import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.RealmModel;
@@ -34,6 +35,7 @@ public abstract class AbstractLoginService {
protected RealmModel realm;
protected TokenManager tokenManager;
+ protected AuthenticationManager authManager = new AuthenticationManager();
public AbstractLoginService(RealmModel realm, TokenManager tokenManager) {
this.realm = realm;
@@ -69,7 +71,7 @@ public abstract class AbstractLoginService {
redirectUri.queryParam("state", state);
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
if (realm.isCookieLoginAllowed()) {
- location.cookie(tokenManager.createLoginCookie(realm, accessCode.getUser(), uriInfo));
+ location.cookie(authManager.createLoginCookie(realm, accessCode.getUser(), uriInfo));
}
return location.build();
}
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 5408c92..b84eb7a 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -54,7 +54,7 @@ public class KeycloakApplication extends Application {
singletons.add(filter);
classes.add(KeycloakSessionResponseFilter.class);
classes.add(SkeletonKeyContextResolver.class);
- classes.add(RegistrationService.class);
+ classes.add(SaasService.class);
}
protected KeycloakSessionFactory createSessionFactory() {
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index b2db4f4..d9319ca 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -5,8 +5,6 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.TokenManager;
-import org.keycloak.services.models.KeycloakSession;
-import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RoleModel;
import org.keycloak.services.models.UserModel;
@@ -88,7 +86,7 @@ public class RealmsResource {
}
SocialService socialService = new SocialService(realm, tokenManager, socialRequestManager);
resourceContext.initResource(socialService);
- return socialService;
+ return socialService;
}
}.call();
}
@@ -121,7 +119,7 @@ public class RealmsResource {
RealmManager realmManager = new RealmManager(session);
RealmModel defaultRealm = realmManager.getRealm(RealmModel.DEFAULT_REALM);
UserModel realmCreator = new AuthenticationManager().authenticateBearerToken(defaultRealm, headers);
- RoleModel creatorRole = defaultRealm.getRole(RegistrationService.REALM_CREATOR_ROLE);
+ RoleModel creatorRole = defaultRealm.getRole(SaasService.REALM_CREATOR_ROLE);
if (!defaultRealm.hasRole(realmCreator, creatorRole)) {
logger.warn("not a realm creator");
throw new NotAuthorizedException("Bearer");
diff --git a/services/src/main/java/org/keycloak/services/resources/SaaSService.java b/services/src/main/java/org/keycloak/services/resources/SaaSService.java
new file mode 100755
index 0000000..93a3e48
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/SaaSService.java
@@ -0,0 +1,296 @@
+package org.keycloak.services.resources;
+
+import org.jboss.resteasy.logging.Logger;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.HttpResponse;
+import org.jboss.resteasy.spi.NotImplementedYetException;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.models.KeycloakSession;
+import org.keycloak.services.models.RealmModel;
+import org.keycloak.services.models.RoleModel;
+import org.keycloak.services.models.UserModel;
+import org.keycloak.services.models.UserCredentialModel;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NewCookie;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Path("/saas")
+public class SaasService {
+ protected static final Logger logger = Logger.getLogger(SaasService.class);
+ public static final String REALM_CREATOR_ROLE = "realm-creator";
+ public static final String SAAS_IDENTITY_COOKIE = "KEYCLOAK_SAAS_IDENTITY";
+
+ @Context
+ protected UriInfo uriInfo;
+
+ @Context
+ protected HttpRequest request;
+
+ @Context
+ HttpResponse response;
+
+ protected String saasLoginPath = "/saas/saas-login.jsp";
+ protected String saasRegisterPath = "/saas/saas-register.jsp";
+ protected String adminPath = "/saas/admin/index.html";
+ protected AuthenticationManager authManager = new AuthenticationManager();
+
+ public static class WhoAmI {
+ protected String userId;
+ protected String displayName;
+
+ public WhoAmI() {
+ }
+
+ public WhoAmI(String userId, String displayName) {
+ this.userId = userId;
+ this.displayName = displayName;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(String displayName) {
+ this.displayName = displayName;
+ }
+ }
+
+ @Path("whoami")
+ @GET
+ @Produces("application/json")
+ public Response whoAmI(final @Context HttpHeaders headers) {
+ return new Transaction() {
+ @Override
+ public Response callImpl()
+ {
+ logger.info("WHOAMI start.");
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel realm = realmManager.defaultRealm();
+ if (realm == null) throw new NotFoundException();
+ UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
+ if (user == null) {
+ return Response.status(404).build();
+ }
+ logger.info("WHOAMI: " + user.getLoginName());
+ return Response.ok(new WhoAmI(user.getLoginName(), user.getLoginName())).build();
+ }
+ }.call();
+ }
+
+ @Path("isLoggedIn.js")
+ @GET
+ @Produces("application/javascript")
+ public String isLoggedIn(final @Context HttpHeaders headers) {
+ return new Transaction() {
+ @Override
+ public String callImpl()
+ {
+ logger.info("WHOAMI Javascript start.");
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel realm = realmManager.defaultRealm();
+ if (realm == null) {
+ return "var keycloakCookieLoggedIn = false;";
+
+ }
+ UserModel user = authManager.authenticateSaasIdentityCookie(realm, uriInfo, headers);
+ if (user == null) {
+ return "var keycloakCookieLoggedIn = false;";
+ }
+ logger.info("WHOAMI: " + user.getLoginName());
+ return "var keycloakCookieLoggedIn = true;";
+ }
+ }.call();
+ }
+
+
+ public static UriBuilder contextRoot(UriInfo uriInfo) {
+ return UriBuilder.fromUri(uriInfo.getBaseUri()).replacePath("/auth-server");
+ }
+
+ public static UriBuilder saasCookiePath(UriInfo uriInfo) {
+ return contextRoot(uriInfo).path("rest").path(SaasService.class);
+ }
+
+
+
+ @Path("logout")
+ @GET
+ public void logout() {
+ new Transaction() {
+ @Override
+ protected void runImpl() {
+ authManager.expireSaasIdentityCookie(uriInfo);
+ request.forward(saasLoginPath);
+ }
+ }.run();
+ }
+
+ @Path("logout-cookie")
+ @GET
+ public void logoutCookie() {
+ logger.info("*** logoutCookie");
+ new Transaction() {
+ @Override
+ protected void runImpl() {
+ authManager.expireSaasIdentityCookie(uriInfo);
+ }
+ }.run();
+ }
+
+
+ @Path("login")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public void processLogin(final MultivaluedMap<String, String> formData) {
+ logger.info("processLogin start");
+ new Transaction() {
+ @Override
+ protected void runImpl() {
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel realm = realmManager.defaultRealm();
+ if (realm == null) throw new NotFoundException();
+
+ if (!realm.isEnabled()) {
+ throw new NotImplementedYetException();
+ }
+ String username = formData.getFirst("username");
+ UserModel user = realm.getUser(username);
+ if (user == null) {
+ logger.info("Not Authenticated! Incorrect user name");
+ request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Incorrect user name.");
+ request.forward(saasLoginPath);
+ return;
+ }
+ if (!user.isEnabled()) {
+ logger.info("NAccount is disabled, contact admin.");
+ request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Account is disabled, contact admin.");
+ request.forward(saasLoginPath);
+ return;
+ }
+
+ boolean authenticated = authManager.authenticateForm(realm, user, formData);
+ if (!authenticated) {
+ logger.info("Not Authenticated! Invalid credentials");
+ request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid credentials.");
+ request.forward(saasLoginPath);
+ return;
+ }
+
+ NewCookie cookie = authManager.createSaasIdentityCookie(realm, user, uriInfo);
+ response.addNewCookie(cookie);
+ request.forward(adminPath);
+ }
+ }.run();
+ }
+
+ @Path("registrations")
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response register(final UserRepresentation newUser) {
+ return new Transaction() {
+ @Override
+ protected Response callImpl() {
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel defaultRealm = realmManager.defaultRealm();
+ UserModel user = registerMe(defaultRealm, newUser);
+ if (user == null) {
+ return Response.status(400).type("text/plain").entity("Already exists").build();
+ }
+ URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
+ return Response.created(uri).build();
+ }
+ }.call();
+ }
+
+ @Path("registrations")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response processRegister(final @FormParam("name") String name,
+ final @FormParam("email") String email,
+ final @FormParam("username") String username,
+ final @FormParam("password") String password,
+ final @FormParam("password-confirm") String confirm) {
+ if (!password.equals(confirm)) {
+ request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Password confirmation doesn't match.");
+ request.forward(saasRegisterPath);
+ return null;
+ }
+ return new Transaction() {
+ @Override
+ protected Response callImpl() {
+ RealmManager realmManager = new RealmManager(session);
+ RealmModel defaultRealm = realmManager.defaultRealm();
+ UserRepresentation newUser = new UserRepresentation();
+ newUser.setUsername(username);
+ newUser.credential(RequiredCredentialRepresentation.PASSWORD, password, false);
+ UserModel user = registerMe(defaultRealm, newUser);
+ if (user == null) {
+ request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Username already exists.");
+ request.forward(saasRegisterPath);
+ return null;
+
+ }
+ NewCookie cookie = authManager.createSaasIdentityCookie(defaultRealm, user, uriInfo);
+ return Response.status(302).location(contextRoot(uriInfo).path(adminPath).build()).cookie(cookie).build();
+ }
+ }.call();
+ }
+
+
+ protected UserModel registerMe(RealmModel defaultRealm, UserRepresentation newUser) {
+ if (!defaultRealm.isEnabled()) {
+ throw new ForbiddenException();
+ }
+ if (!defaultRealm.isRegistrationAllowed()) {
+ throw new ForbiddenException();
+ }
+ UserModel user = defaultRealm.getUser(newUser.getUsername());
+ if (user != null) {
+ return null;
+ }
+
+ user = defaultRealm.addUser(newUser.getUsername());
+ for (CredentialRepresentation cred : newUser.getCredentials()) {
+ UserCredentialModel credModel = new UserCredentialModel();
+ credModel.setType(cred.getType());
+ credModel.setValue(cred.getValue());
+ defaultRealm.updateCredential(user, credModel);
+ }
+ RoleModel realmCreator = defaultRealm.getRole(REALM_CREATOR_ROLE);
+ defaultRealm.grantRole(user, realmCreator);
+ return user;
+ }
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index b16c1ef..ba4d265 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -49,7 +49,6 @@ public class TokenService extends AbstractLoginService {
@Context
protected SecurityContext securityContext;
- protected AuthenticationManager authManager = new AuthenticationManager();
private ResourceAdminManager resourceAdminManager = new ResourceAdminManager();
public TokenService(RealmModel realm, TokenManager tokenManager) {
@@ -115,7 +114,7 @@ public class TokenService extends AbstractLoginService {
throw new NotAuthorizedException("FORM");
}
tokenManager = new TokenManager();
- SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
+ SkeletonKeyToken token = authManager.createIdentityToken(realm, username);
String encoded = tokenManager.encodeToken(realm, token);
AccessTokenResponse res = accessTokenResponse(token, encoded);
return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
diff --git a/services/src/test/java/org/keycloak/test/ImportTest.java b/services/src/test/java/org/keycloak/test/ImportTest.java
index 1c783e4..03f945f 100755
--- a/services/src/test/java/org/keycloak/test/ImportTest.java
+++ b/services/src/test/java/org/keycloak/test/ImportTest.java
@@ -12,10 +12,13 @@ import org.keycloak.services.models.KeycloakSession;
import org.keycloak.services.models.KeycloakSessionFactory;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
+import org.keycloak.services.models.ResourceModel;
import org.keycloak.services.models.UserModel;
import org.keycloak.services.resources.KeycloakApplication;
-import org.keycloak.services.resources.RegistrationService;
+import org.keycloak.services.resources.SaasService;
+import org.keycloak.services.resources.SaasService;
+import java.util.List;
import java.util.Set;
/**
@@ -56,17 +59,21 @@ public class ImportTest {
defaultRealm.setRegistrationAllowed(true);
manager.generateRealmKeys(defaultRealm);
defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
- defaultRealm.addRole(RegistrationService.REALM_CREATOR_ROLE);
+ defaultRealm.addRole(SaasService.REALM_CREATOR_ROLE);
RealmRepresentation rep = KeycloakTestBase.loadJson("testrealm.json");
RealmModel realm = manager.createRealm("demo", rep.getRealm());
manager.importRealm(rep, realm);
+ List<RequiredCredentialModel> creds = realm.getRequiredCredentials();
+ Assert.assertEquals(1, creds.size());
UserModel user = realm.getUser("loginclient");
Assert.assertNotNull(user);
Set<String> scopes = realm.getScope(user);
System.out.println("Scopes size: " + scopes.size());
Assert.assertTrue(scopes.contains("*"));
+ List<ResourceModel> resources = realm.getResources();
+ Assert.assertEquals(2, resources.size());
}
diff --git a/services/src/test/java/org/keycloak/test/InstallationManager.java b/services/src/test/java/org/keycloak/test/InstallationManager.java
index bd4724e..63e5d1d 100755
--- a/services/src/test/java/org/keycloak/test/InstallationManager.java
+++ b/services/src/test/java/org/keycloak/test/InstallationManager.java
@@ -3,7 +3,8 @@ package org.keycloak.test;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
-import org.keycloak.services.resources.RegistrationService;
+import org.keycloak.services.resources.SaasService;
+import org.keycloak.services.resources.SaasService;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -21,7 +22,7 @@ public class InstallationManager {
defaultRealm.setRegistrationAllowed(true);
manager.generateRealmKeys(defaultRealm);
defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
- defaultRealm.addRole(RegistrationService.REALM_CREATOR_ROLE);
+ defaultRealm.addRole(SaasService.REALM_CREATOR_ROLE);
}
public boolean isInstalled(RealmManager manager) {
diff --git a/services/src/test/java/org/keycloak/test/RealmCreationTest.java b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
index 7003890..fad6c34 100755
--- a/services/src/test/java/org/keycloak/test/RealmCreationTest.java
+++ b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
@@ -64,7 +64,7 @@ public class RealmCreationTest {
user.credential(RequiredCredentialRepresentation.PASSWORD, "geheim", false);
WebTarget target = client.target(generateURL("/"));
- Response response = target.path("registrations").request().post(Entity.json(user));
+ Response response = target.path("saas/registrations").request().post(Entity.json(user));
Assert.assertEquals(201, response.getStatus());
response.close();