Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c07f7bb1e |
No files matched your search
@@ -1,35 +1,4 @@
|
|||||||
keycloak
|
keycloak
|
||||||
========
|
========
|
||||||
|
|
||||||
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
|
SSO Service for web apps and REST services.
|
||||||
and video tutorials.
|
|
||||||
|
|
||||||
Keycloak is an SSO Service for web apps and REST services.
|
|
||||||
It can be used for social applications as well as enterprise applications. It is based on OpenID Connect with SAML support in the works.
|
|
||||||
Here's some of the features:
|
|
||||||
|
|
||||||
* SSO and Single Log Out for browser applications
|
|
||||||
* Social Broker. Enable Google, Facebook, Yahoo, Twitter social login with no code required.
|
|
||||||
* Optional LDAP/Active Directory integration
|
|
||||||
* Optional User Registration
|
|
||||||
* Password and TOTP support (via Google Authenticator). Client cert auth coming soon.
|
|
||||||
* User session management from both admin and user perspective
|
|
||||||
* Customizable themes for user facing pages: login, grant pages, account management, emails, and admin console all customizable!
|
|
||||||
* OAuth Bearer token auth for REST Services
|
|
||||||
* Integrated Browser App to REST Service token propagation
|
|
||||||
* Admin REST API
|
|
||||||
* OAuth 2.0 Grant requests
|
|
||||||
* CORS Support
|
|
||||||
* CORS Web Origin management and validation
|
|
||||||
* Completely centrally managed user and role mapping metadata. Minimal configuration at the application side
|
|
||||||
* Admin Console for managing users, roles, role mappings, applications, user sessions, allowed CORS web origins, and OAuth clients.
|
|
||||||
* Deployable as a WAR, appliance, or an Openshift cloud service (SaaS).
|
|
||||||
* Supports JBoss AS7, EAP 6.x, and Wildfly applications. Plans to support Node.js, RAILS, GRAILS, and other non-Java applications.
|
|
||||||
* Javascript/HTML 5 adapter for pure Javascript apps
|
|
||||||
* Session management from admin console
|
|
||||||
* Revocation policies
|
|
||||||
* Password policies
|
|
||||||
* OpenID Connect Support
|
|
||||||
|
|
||||||
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
|
|
||||||
and video tutorials.
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<project>
|
<project>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-events-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-events-api</artifactId>
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
<name>Keycloak Events API</name>
|
<name>Keycloak Audit API</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
+25
-25
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
@@ -12,14 +12,14 @@ import java.util.List;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class EventBuilder {
|
public class Audit {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(EventBuilder.class);
|
private static final Logger log = Logger.getLogger(Audit.class);
|
||||||
|
|
||||||
private List<EventListenerProvider> listeners;
|
private List<AuditListener> listeners;
|
||||||
private Event event;
|
private Event event;
|
||||||
|
|
||||||
public EventBuilder(List<EventListenerProvider> listeners, RealmModel realm, String ipAddress) {
|
public Audit(List<AuditListener> listeners, RealmModel realm, String ipAddress) {
|
||||||
this.listeners = listeners;
|
this.listeners = listeners;
|
||||||
this.event = new Event();
|
this.event = new Event();
|
||||||
|
|
||||||
@@ -27,60 +27,60 @@ public class EventBuilder {
|
|||||||
ipAddress(ipAddress);
|
ipAddress(ipAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBuilder() {
|
Audit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder realm(RealmModel realm) {
|
public Audit realm(RealmModel realm) {
|
||||||
event.setRealmId(realm.getId());
|
event.setRealmId(realm.getId());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder realm(String realmId) {
|
public Audit realm(String realmId) {
|
||||||
event.setRealmId(realmId);
|
event.setRealmId(realmId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder client(ClientModel client) {
|
public Audit client(ClientModel client) {
|
||||||
event.setClientId(client.getClientId());
|
event.setClientId(client.getClientId());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder client(String clientId) {
|
public Audit client(String clientId) {
|
||||||
event.setClientId(clientId);
|
event.setClientId(clientId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder user(UserModel user) {
|
public Audit user(UserModel user) {
|
||||||
event.setUserId(user.getId());
|
event.setUserId(user.getId());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder user(String userId) {
|
public Audit user(String userId) {
|
||||||
event.setUserId(userId);
|
event.setUserId(userId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder session(UserSessionModel session) {
|
public Audit session(UserSessionModel session) {
|
||||||
event.setSessionId(session.getId());
|
event.setSessionId(session.getId());
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder session(String sessionId) {
|
public Audit session(String sessionId) {
|
||||||
event.setSessionId(sessionId);
|
event.setSessionId(sessionId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder ipAddress(String ipAddress) {
|
public Audit ipAddress(String ipAddress) {
|
||||||
event.setIpAddress(ipAddress);
|
event.setIpAddress(ipAddress);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder event(EventType e) {
|
public Audit event(EventType e) {
|
||||||
event.setType(e);
|
event.setEvent(e);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder detail(String key, String value) {
|
public Audit detail(String key, String value) {
|
||||||
if (value == null || value.equals("")) {
|
if (value == null || value.equals("")) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ public class EventBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder removeDetail(String key) {
|
public Audit removeDetail(String key) {
|
||||||
if (event.getDetails() != null) {
|
if (event.getDetails() != null) {
|
||||||
event.getDetails().remove(key);
|
event.getDetails().remove(key);
|
||||||
}
|
}
|
||||||
@@ -108,19 +108,19 @@ public class EventBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void error(String error) {
|
public void error(String error) {
|
||||||
event.setType(EventType.valueOf(event.getType().name() + "_ERROR"));
|
event.setEvent(EventType.valueOf(event.getEvent().name() + "_ERROR"));
|
||||||
event.setError(error);
|
event.setError(error);
|
||||||
send();
|
send();
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder clone() {
|
public Audit clone() {
|
||||||
EventBuilder clone = new EventBuilder();
|
Audit clone = new Audit();
|
||||||
clone.listeners = listeners;
|
clone.listeners = listeners;
|
||||||
clone.event = event.clone();
|
clone.event = event.clone();
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBuilder reset() {
|
public Audit reset() {
|
||||||
Event old = event;
|
Event old = event;
|
||||||
|
|
||||||
event = new Event();
|
event = new Event();
|
||||||
@@ -136,11 +136,11 @@ public class EventBuilder {
|
|||||||
event.setTime(System.currentTimeMillis());
|
event.setTime(System.currentTimeMillis());
|
||||||
|
|
||||||
if (listeners != null) {
|
if (listeners != null) {
|
||||||
for (EventListenerProvider l : listeners) {
|
for (AuditListener l : listeners) {
|
||||||
try {
|
try {
|
||||||
l.onEvent(event);
|
l.onEvent(event);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.error("Failed to send type to " + l, t);
|
log.error("Failed to send event to " + l, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,11 +1,11 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface EventListenerProvider extends Provider {
|
public interface AuditListener extends Provider {
|
||||||
|
|
||||||
public void onEvent(Event event);
|
public void onEvent(Event event);
|
||||||
|
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface EventStoreProviderFactory extends ProviderFactory<EventStoreProvider> {
|
public interface AuditListenerFactory extends ProviderFactory<AuditListener> {
|
||||||
|
|
||||||
}
|
}
|
||||||
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class EventStoreSpi implements Spi {
|
public class AuditListenerSpi implements Spi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "eventsStore";
|
return "audit-listener";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends Provider> getProviderClass() {
|
public Class<? extends Provider> getProviderClass() {
|
||||||
return EventStoreProvider.class;
|
return AuditListener.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
return EventStoreProviderFactory.class;
|
return AuditListenerFactory.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface EventStoreProvider extends EventListenerProvider {
|
public interface AuditProvider extends AuditListener {
|
||||||
|
|
||||||
public EventQuery createQuery();
|
public EventQuery createQuery();
|
||||||
|
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface EventListenerProviderFactory extends ProviderFactory<EventListenerProvider> {
|
public interface AuditProviderFactory extends ProviderFactory<AuditProvider> {
|
||||||
|
|
||||||
}
|
}
|
||||||
Executable → Regular
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.models;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class UserSpi implements Spi {
|
public class AuditProviderSpi implements Spi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "user";
|
return "audit";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends Provider> getProviderClass() {
|
public Class<? extends Provider> getProviderClass() {
|
||||||
return UserProvider.class;
|
return AuditProvider.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
return UserProviderFactory.class;
|
return AuditProviderFactory.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Executable → Regular
+1
-2
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
@@ -17,7 +17,6 @@ public interface Details {
|
|||||||
String REMEMBER_ME = "remember_me";
|
String REMEMBER_ME = "remember_me";
|
||||||
String TOKEN_ID = "token_id";
|
String TOKEN_ID = "token_id";
|
||||||
String REFRESH_TOKEN_ID = "refresh_token_id";
|
String REFRESH_TOKEN_ID = "refresh_token_id";
|
||||||
String VALIDATE_ACCESS_TOKEN = "validate_access_token";
|
|
||||||
String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id";
|
String UPDATED_REFRESH_TOKEN_ID = "updated_refresh_token_id";
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
-3
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
@@ -10,7 +10,6 @@ public interface Errors {
|
|||||||
String CLIENT_NOT_FOUND = "client_not_found";
|
String CLIENT_NOT_FOUND = "client_not_found";
|
||||||
String CLIENT_DISABLED = "client_disabled";
|
String CLIENT_DISABLED = "client_disabled";
|
||||||
String INVALID_CLIENT_CREDENTIALS = "invalid_client_credentials";
|
String INVALID_CLIENT_CREDENTIALS = "invalid_client_credentials";
|
||||||
String INVALID_CLIENT = "invalid_client";
|
|
||||||
|
|
||||||
String USER_NOT_FOUND = "user_not_found";
|
String USER_NOT_FOUND = "user_not_found";
|
||||||
String USER_DISABLED = "user_disabled";
|
String USER_DISABLED = "user_disabled";
|
||||||
@@ -19,7 +18,6 @@ public interface Errors {
|
|||||||
|
|
||||||
String USERNAME_MISSING = "username_missing";
|
String USERNAME_MISSING = "username_missing";
|
||||||
String USERNAME_IN_USE = "username_in_use";
|
String USERNAME_IN_USE = "username_in_use";
|
||||||
String EMAIL_IN_USE = "email_in_use";
|
|
||||||
|
|
||||||
String INVALID_REDIRECT_URI = "invalid_redirect_uri";
|
String INVALID_REDIRECT_URI = "invalid_redirect_uri";
|
||||||
String INVALID_CODE = "invalid_code";
|
String INVALID_CODE = "invalid_code";
|
||||||
+7
-7
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -10,7 +10,7 @@ public class Event {
|
|||||||
|
|
||||||
private long time;
|
private long time;
|
||||||
|
|
||||||
private EventType type;
|
private EventType event;
|
||||||
|
|
||||||
private String realmId;
|
private String realmId;
|
||||||
|
|
||||||
@@ -34,12 +34,12 @@ public class Event {
|
|||||||
this.time = time;
|
this.time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventType getType() {
|
public EventType getEvent() {
|
||||||
return type;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(EventType type) {
|
public void setEvent(EventType event) {
|
||||||
this.type = type;
|
this.event = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealmId() {
|
public String getRealmId() {
|
||||||
@@ -101,7 +101,7 @@ public class Event {
|
|||||||
public Event clone() {
|
public Event clone() {
|
||||||
Event clone = new Event();
|
Event clone = new Event();
|
||||||
clone.time = time;
|
clone.time = time;
|
||||||
clone.type = type;
|
clone.event = event;
|
||||||
clone.realmId = realmId;
|
clone.realmId = realmId;
|
||||||
clone.clientId = clientId;
|
clone.clientId = clientId;
|
||||||
clone.userId = userId;
|
clone.userId = userId;
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface EventQuery {
|
public interface EventQuery {
|
||||||
|
|
||||||
public EventQuery type(EventType... types);
|
public EventQuery event(EventType... events);
|
||||||
|
|
||||||
public EventQuery realm(String realmId);
|
public EventQuery realm(String realmId);
|
||||||
|
|
||||||
Executable → Regular
+1
-3
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.events;
|
package org.keycloak.audit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
@@ -14,8 +14,6 @@ public enum EventType {
|
|||||||
CODE_TO_TOKEN,
|
CODE_TO_TOKEN,
|
||||||
CODE_TO_TOKEN_ERROR,
|
CODE_TO_TOKEN_ERROR,
|
||||||
REFRESH_TOKEN,
|
REFRESH_TOKEN,
|
||||||
VALIDATE_ACCESS_TOKEN,
|
|
||||||
VALIDATE_ACCESS_TOKEN_ERROR,
|
|
||||||
REFRESH_TOKEN_ERROR,
|
REFRESH_TOKEN_ERROR,
|
||||||
SOCIAL_LINK,
|
SOCIAL_LINK,
|
||||||
SOCIAL_LINK_ERROR,
|
SOCIAL_LINK_ERROR,
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
org.keycloak.audit.AuditProviderSpi
|
||||||
|
org.keycloak.audit.AuditListenerSpi
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<project>
|
<project>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-events-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-events-email</artifactId>
|
<artifactId>keycloak-audit-email</artifactId>
|
||||||
<name>Keycloak Events Email Provider</name>
|
<name>Keycloak Audit Email Provider</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-events-api</artifactId>
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
Executable → Regular
+17
-16
@@ -1,48 +1,49 @@
|
|||||||
package org.keycloak.events.email;
|
package org.keycloak.audit.email;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
import org.keycloak.email.EmailException;
|
import org.keycloak.email.EmailException;
|
||||||
import org.keycloak.email.EmailProvider;
|
import org.keycloak.email.EmailProvider;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RealmProvider;
|
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class EmailEventListenerProvider implements EventListenerProvider {
|
public class EmailAuditListener implements AuditListener {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(EmailEventListenerProvider.class);
|
private static final Logger log = Logger.getLogger(EmailAuditListener.class);
|
||||||
|
|
||||||
private KeycloakSession session;
|
private KeycloakSession keycloakSession;
|
||||||
private RealmProvider model;
|
|
||||||
private EmailProvider emailProvider;
|
private EmailProvider emailProvider;
|
||||||
private Set<EventType> includedEvents;
|
private Set<EventType> includedEvents;
|
||||||
|
|
||||||
public EmailEventListenerProvider(KeycloakSession session, EmailProvider emailProvider, Set<EventType> includedEvents) {
|
public EmailAuditListener(KeycloakSession keycloakSession, EmailProvider emailProvider, Set<EventType> includedEvents) {
|
||||||
this.session = session;
|
this.keycloakSession = keycloakSession;
|
||||||
this.model = session.realms();
|
|
||||||
this.emailProvider = emailProvider;
|
this.emailProvider = emailProvider;
|
||||||
this.includedEvents = includedEvents;
|
this.includedEvents = includedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) {
|
public void onEvent(Event event) {
|
||||||
if (includedEvents.contains(event.getType())) {
|
if (includedEvents.contains(event.getEvent())) {
|
||||||
if (event.getRealmId() != null && event.getUserId() != null) {
|
if (event.getRealmId() != null && event.getUserId() != null) {
|
||||||
RealmModel realm = model.getRealm(event.getRealmId());
|
RealmModel realm = keycloakSession.getRealm(event.getRealmId());
|
||||||
UserModel user = session.users().getUserById(event.getUserId(), realm);
|
UserModel user = realm.getUserById(event.getUserId());
|
||||||
if (user != null && user.getEmail() != null && user.isEmailVerified()) {
|
if (user != null && user.getEmail() != null && user.isEmailVerified()) {
|
||||||
try {
|
try {
|
||||||
emailProvider.setRealm(realm).setUser(user).sendEvent(event);
|
emailProvider.setRealm(realm).setUser(user).sendEvent(event);
|
||||||
} catch (EmailException e) {
|
} catch (EmailException e) {
|
||||||
log.error("Failed to send type mail", e);
|
log.error("Failed to send event mail", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-8
@@ -1,11 +1,12 @@
|
|||||||
package org.keycloak.events.email;
|
package org.keycloak.audit.email;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.events.EventListenerProviderFactory;
|
import org.keycloak.audit.AuditListenerFactory;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
import org.keycloak.email.EmailProvider;
|
import org.keycloak.email.EmailProvider;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -14,7 +15,7 @@ import java.util.Set;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class EmailEventListenerProviderFactory implements EventListenerProviderFactory {
|
public class EmailAuditListenerFactory implements AuditListenerFactory {
|
||||||
|
|
||||||
private static final Set<EventType> SUPPORTED_EVENTS = new HashSet<EventType>();
|
private static final Set<EventType> SUPPORTED_EVENTS = new HashSet<EventType>();
|
||||||
static {
|
static {
|
||||||
@@ -24,9 +25,10 @@ public class EmailEventListenerProviderFactory implements EventListenerProviderF
|
|||||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventListenerProvider create(KeycloakSession session) {
|
public AuditListener create(ProviderSession providerSession) {
|
||||||
EmailProvider emailProvider = session.getProvider(EmailProvider.class);
|
KeycloakSession keycloakSession = providerSession.getProvider(KeycloakSession.class);
|
||||||
return new EmailEventListenerProvider(session, emailProvider, includedEvents);
|
EmailProvider emailProvider = providerSession.getProvider(EmailProvider.class);
|
||||||
|
return new EmailAuditListener(keycloakSession, emailProvider, includedEvents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.audit.email.EmailAuditListenerFactory
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<project>
|
<project>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-events-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-events-jboss-logging</artifactId>
|
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||||
<name>Keycloak Events JBoss Logging Provider</name>
|
<name>Keycloak Audit JBoss Logging Provider</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -26,13 +26,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-events-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
+7
-7
@@ -1,19 +1,19 @@
|
|||||||
package org.keycloak.events.log;
|
package org.keycloak.audit.log;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JBossLoggingEventListenerProvider implements EventListenerProvider {
|
public class JBossLoggingAuditListener implements AuditListener {
|
||||||
|
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
|
|
||||||
public JBossLoggingEventListenerProvider(Logger logger) {
|
public JBossLoggingAuditListener(Logger logger) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +24,8 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider
|
|||||||
if (logger.isEnabled(level)) {
|
if (logger.isEnabled(level)) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("type=");
|
sb.append("event=");
|
||||||
sb.append(event.getType());
|
sb.append(event.getEvent());
|
||||||
sb.append(", realmId=");
|
sb.append(", realmId=");
|
||||||
sb.append(event.getRealmId());
|
sb.append(event.getRealmId());
|
||||||
sb.append(", clientId=");
|
sb.append(", clientId=");
|
||||||
+8
-8
@@ -1,23 +1,23 @@
|
|||||||
package org.keycloak.events.log;
|
package org.keycloak.audit.log;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.audit.AuditListener;
|
||||||
import org.keycloak.events.EventListenerProviderFactory;
|
import org.keycloak.audit.AuditListenerFactory;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JBossLoggingEventListenerProviderFactory implements EventListenerProviderFactory {
|
public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
||||||
|
|
||||||
public static final String ID = "jboss-logging";
|
public static final String ID = "jboss-logging";
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger("org.keycloak.events");
|
private static final Logger logger = Logger.getLogger("org.keycloak.audit");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventListenerProvider create(KeycloakSession session) {
|
public AuditListener create(ProviderSession providerSession) {
|
||||||
return new JBossLoggingEventListenerProvider(logger);
|
return new JBossLoggingAuditListener(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.audit.log.JBossLoggingAuditListenerFactory
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<project>
|
<project>
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-events-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-events-jpa</artifactId>
|
<artifactId>keycloak-audit-jpa</artifactId>
|
||||||
<name>Keycloak Events Store JPA Provider</name>
|
<name>Keycloak Audit JPA Provider</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -21,19 +21,13 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-connections-jpa</artifactId>
|
<artifactId>keycloak-audit-tests</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-events-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -58,5 +52,16 @@
|
|||||||
<artifactId>jackson-core-asl</artifactId>
|
<artifactId>jackson-core-asl</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
+7
-18
@@ -1,46 +1,35 @@
|
|||||||
package org.keycloak.events.jpa;
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.Table;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name="EVENT_ENTITY")
|
|
||||||
public class EventEntity {
|
public class EventEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name="ID", length = 36)
|
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@Column(name="TIME")
|
|
||||||
private long time;
|
private long time;
|
||||||
|
|
||||||
@Column(name="TYPE")
|
private String event;
|
||||||
private String type;
|
|
||||||
|
|
||||||
@Column(name="REALM_ID")
|
|
||||||
private String realmId;
|
private String realmId;
|
||||||
|
|
||||||
@Column(name="CLIENT_ID")
|
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
@Column(name="USER_ID")
|
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
@Column(name="SESSION_ID")
|
|
||||||
private String sessionId;
|
private String sessionId;
|
||||||
|
|
||||||
@Column(name="IP_ADDRESS")
|
|
||||||
private String ipAddress;
|
private String ipAddress;
|
||||||
|
|
||||||
@Column(name="ERROR")
|
|
||||||
private String error;
|
private String error;
|
||||||
|
|
||||||
@Column(name="DETAILS_JSON", length = 2550)
|
@Column(length = 2550)
|
||||||
private String detailsJson;
|
private String detailsJson;
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
@@ -59,12 +48,12 @@ public class EventEntity {
|
|||||||
this.time = time;
|
this.time = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getEvent() {
|
||||||
return type;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(String type) {
|
public void setEvent(String event) {
|
||||||
this.type = type;
|
this.event = event;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealmId() {
|
public String getRealmId() {
|
||||||
+27
-11
@@ -1,12 +1,12 @@
|
|||||||
package org.keycloak.events.jpa;
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
import org.codehaus.jackson.type.TypeReference;
|
import org.codehaus.jackson.type.TypeReference;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.events.EventStoreProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.events.EventQuery;
|
import org.keycloak.audit.EventQuery;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.EntityTransaction;
|
import javax.persistence.EntityTransaction;
|
||||||
@@ -18,18 +18,18 @@ import java.util.UUID;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JpaEventStoreProvider implements EventStoreProvider {
|
public class JpaAuditProvider implements AuditProvider {
|
||||||
|
|
||||||
private static final ObjectMapper mapper = new ObjectMapper();
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
private static final TypeReference<Map<String, String>> mapType = new TypeReference<Map<String, String>>() {
|
private static final TypeReference<Map<String, String>> mapType = new TypeReference<Map<String, String>>() {
|
||||||
};
|
};
|
||||||
private static final Logger logger = Logger.getLogger(JpaEventStoreProvider.class);
|
private static final Logger logger = Logger.getLogger(JpaAuditProvider.class);
|
||||||
|
|
||||||
private EntityManager em;
|
private EntityManager em;
|
||||||
private EntityTransaction tx;
|
private EntityTransaction tx;
|
||||||
private Set<EventType> includedEvents;
|
private Set<EventType> includedEvents;
|
||||||
|
|
||||||
public JpaEventStoreProvider(EntityManager em, Set<EventType> includedEvents) {
|
public JpaAuditProvider(EntityManager em, Set<EventType> includedEvents) {
|
||||||
this.em = em;
|
this.em = em;
|
||||||
this.includedEvents = includedEvents;
|
this.includedEvents = includedEvents;
|
||||||
}
|
}
|
||||||
@@ -41,35 +41,51 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
beginTx();
|
||||||
em.createQuery("delete from EventEntity").executeUpdate();
|
em.createQuery("delete from EventEntity").executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear(String realmId) {
|
public void clear(String realmId) {
|
||||||
|
beginTx();
|
||||||
em.createQuery("delete from EventEntity where realmId = :realmId").setParameter("realmId", realmId).executeUpdate();
|
em.createQuery("delete from EventEntity where realmId = :realmId").setParameter("realmId", realmId).executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear(String realmId, long olderThan) {
|
public void clear(String realmId, long olderThan) {
|
||||||
|
beginTx();
|
||||||
em.createQuery("delete from EventEntity where realmId = :realmId and time < :time").setParameter("realmId", realmId).setParameter("time", olderThan).executeUpdate();
|
em.createQuery("delete from EventEntity where realmId = :realmId and time < :time").setParameter("realmId", realmId).setParameter("time", olderThan).executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) {
|
public void onEvent(Event event) {
|
||||||
if (includedEvents.contains(event.getType())) {
|
if (includedEvents.contains(event.getEvent())) {
|
||||||
|
beginTx();
|
||||||
em.persist(convert(event));
|
em.persist(convert(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
if (tx != null) {
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void beginTx() {
|
||||||
|
if (tx == null) {
|
||||||
|
tx = em.getTransaction();
|
||||||
|
tx.begin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EventEntity convert(Event o) {
|
static EventEntity convert(Event o) {
|
||||||
EventEntity e = new EventEntity();
|
EventEntity e = new EventEntity();
|
||||||
e.setId(UUID.randomUUID().toString());
|
e.setId(UUID.randomUUID().toString());
|
||||||
e.setTime(o.getTime());
|
e.setTime(o.getTime());
|
||||||
e.setType(o.getType().toString());
|
e.setEvent(o.getEvent().toString());
|
||||||
e.setRealmId(o.getRealmId());
|
e.setRealmId(o.getRealmId());
|
||||||
e.setClientId(o.getClientId());
|
e.setClientId(o.getClientId());
|
||||||
e.setUserId(o.getUserId());
|
e.setUserId(o.getUserId());
|
||||||
@@ -87,7 +103,7 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
|||||||
static Event convert(EventEntity o) {
|
static Event convert(EventEntity o) {
|
||||||
Event e = new Event();
|
Event e = new Event();
|
||||||
e.setTime(o.getTime());
|
e.setTime(o.getTime());
|
||||||
e.setType(EventType.valueOf(o.getType()));
|
e.setEvent(EventType.valueOf(o.getEvent()));
|
||||||
e.setRealmId(o.getRealmId());
|
e.setRealmId(o.getRealmId());
|
||||||
e.setClientId(o.getClientId());
|
e.setClientId(o.getClientId());
|
||||||
e.setUserId(o.getUserId());
|
e.setUserId(o.getUserId());
|
||||||
+15
-10
@@ -1,32 +1,36 @@
|
|||||||
package org.keycloak.events.jpa;
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.events.EventStoreProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.events.EventStoreProviderFactory;
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
import org.keycloak.provider.ProviderSession;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.util.JpaUtils;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
import javax.persistence.Persistence;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
|
public class JpaAuditProviderFactory implements AuditProviderFactory {
|
||||||
|
|
||||||
public static final String ID = "jpa";
|
public static final String ID = "jpa";
|
||||||
|
private EntityManagerFactory emf;
|
||||||
|
|
||||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventStoreProvider create(KeycloakSession session) {
|
public AuditProvider create(ProviderSession providerSession) {
|
||||||
JpaConnectionProvider connection = session.getProvider(JpaConnectionProvider.class);
|
return new JpaAuditProvider(emf.createEntityManager(), includedEvents);
|
||||||
return new JpaEventStoreProvider(connection.getEntityManager(), includedEvents);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
|
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store", JpaUtils.getHibernateProperties());
|
||||||
|
|
||||||
String[] include = config.getArray("include-events");
|
String[] include = config.getArray("include-events");
|
||||||
if (include != null) {
|
if (include != null) {
|
||||||
for (String i : include) {
|
for (String i : include) {
|
||||||
@@ -48,6 +52,7 @@ public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
|
emf.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+8
-8
@@ -1,8 +1,8 @@
|
|||||||
package org.keycloak.events.jpa;
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.events.EventQuery;
|
import org.keycloak.audit.EventQuery;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
@@ -37,12 +37,12 @@ public class JpaEventQuery implements EventQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventQuery type(EventType... types) {
|
public EventQuery event(EventType... events) {
|
||||||
List<String> eventStrings = new LinkedList<String>();
|
List<String> eventStrings = new LinkedList<String>();
|
||||||
for (EventType e : types) {
|
for (EventType e : events) {
|
||||||
eventStrings.add(e.toString());
|
eventStrings.add(e.toString());
|
||||||
}
|
}
|
||||||
predicates.add(root.get("type").in(eventStrings));
|
predicates.add(root.get("event").in(eventStrings));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public class JpaEventQuery implements EventQuery {
|
|||||||
|
|
||||||
List<Event> events = new LinkedList<Event>();
|
List<Event> events = new LinkedList<Event>();
|
||||||
for (EventEntity e : query.getResultList()) {
|
for (EventEntity e : query.getResultList()) {
|
||||||
events.add(JpaEventStoreProvider.convert(e));
|
events.add(JpaAuditProvider.convert(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
return events;
|
return events;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.audit.jpa.JpaAuditProviderFactory
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.keycloak.audit.jpa;
|
||||||
|
|
||||||
|
import org.keycloak.audit.tests.AbstractAuditProviderTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class JpaAuditProviderTest extends AbstractAuditProviderTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProviderId() {
|
||||||
|
return JpaAuditProviderFactory.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||||
|
version="1.0">
|
||||||
|
<persistence-unit name="jpa-keycloak-audit-store" transaction-type="RESOURCE_LOCAL">
|
||||||
|
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||||
|
|
||||||
|
<class>org.keycloak.audit.jpa.EventEntity</class>
|
||||||
|
|
||||||
|
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
|
||||||
|
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
|
||||||
|
<property name="hibernate.connection.username" value="sa"/>
|
||||||
|
<property name="hibernate.connection.password" value=""/>
|
||||||
|
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
|
||||||
|
<property name="hibernate.show_sql" value="false" />
|
||||||
|
<property name="hibernate.format_sql" value="true" />
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
||||||
Executable
+130
@@ -0,0 +1,130 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project>
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.0-beta-3</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-audit-mongo</artifactId>
|
||||||
|
<name>Keycloak Audit Mongo Provider</name>
|
||||||
|
<description/>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-audit-tests</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<keycloak.audit.mongo.host>localhost</keycloak.audit.mongo.host>
|
||||||
|
<keycloak.audit.mongo.port>27018</keycloak.audit.mongo.port>
|
||||||
|
<keycloak.audit.mongo.db>keycloak</keycloak.audit.mongo.db>
|
||||||
|
<keycloak.audit.mongo.clearOnStartup>true</keycloak.audit.mongo.clearOnStartup>
|
||||||
|
<keycloak.audit.mongo.bindIp>127.0.0.1</keycloak.audit.mongo.bindIp>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Postpone tests to "integration-test" phase, so that we can bootstrap embedded mongo on 27018 before running tests -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>test</id>
|
||||||
|
<phase>integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<keycloak.audit.mongo.host>${keycloak.audit.mongo.host}</keycloak.audit.mongo.host>
|
||||||
|
<keycloak.audit.mongo.port>${keycloak.audit.mongo.port}</keycloak.audit.mongo.port>
|
||||||
|
<keycloak.audit.mongo.db>${keycloak.audit.mongo.db}</keycloak.audit.mongo.db>
|
||||||
|
<keycloak.audit.mongo.clearOnStartup>${keycloak.audit.mongo.clearOnStartup}</keycloak.audit.mongo.clearOnStartup>
|
||||||
|
<keycloak.audit.mongo.bindIp>${keycloak.model.mongo.bindIp}</keycloak.audit.mongo.bindIp>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>default-test</id>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Embedded mongo -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.joelittlejohn.embedmongo</groupId>
|
||||||
|
<artifactId>embedmongo-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>start-mongodb</id>
|
||||||
|
<phase>pre-integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>start</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<port>${keycloak.audit.mongo.port}</port>
|
||||||
|
<logging>file</logging>
|
||||||
|
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||||
|
<bindIp>${keycloak.audit.mongo.bindIp}</bindIp>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>stop-mongodb</id>
|
||||||
|
<phase>post-integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>stop</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
+17
-17
@@ -1,12 +1,12 @@
|
|||||||
package org.keycloak.events.mongo;
|
package org.keycloak.audit.mongo;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
import org.keycloak.events.EventStoreProvider;
|
import org.keycloak.audit.AuditProvider;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.events.EventQuery;
|
import org.keycloak.audit.EventQuery;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -15,29 +15,29 @@ import java.util.Set;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class MongoEventStoreProvider implements EventStoreProvider {
|
public class MongoAuditProvider implements AuditProvider {
|
||||||
|
|
||||||
private DBCollection events;
|
private DBCollection audit;
|
||||||
private Set<EventType> includedEvents;
|
private Set<EventType> includedEvents;
|
||||||
|
|
||||||
public MongoEventStoreProvider(DBCollection events, Set<EventType> includedEvents) {
|
public MongoAuditProvider(DBCollection audit, Set<EventType> includedEvents) {
|
||||||
this.events = events;
|
this.audit = audit;
|
||||||
this.includedEvents = includedEvents;
|
this.includedEvents = includedEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventQuery createQuery() {
|
public EventQuery createQuery() {
|
||||||
return new MongoEventQuery(events);
|
return new MongoEventQuery(audit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
events.remove(new BasicDBObject());
|
audit.remove(new BasicDBObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear(String realmId) {
|
public void clear(String realmId) {
|
||||||
events.remove(new BasicDBObject("realmId", realmId));
|
audit.remove(new BasicDBObject("realmId", realmId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,13 +45,13 @@ public class MongoEventStoreProvider implements EventStoreProvider {
|
|||||||
BasicDBObject q = new BasicDBObject();
|
BasicDBObject q = new BasicDBObject();
|
||||||
q.put("realmId", realmId);
|
q.put("realmId", realmId);
|
||||||
q.put("time", new BasicDBObject("$lt", olderThan));
|
q.put("time", new BasicDBObject("$lt", olderThan));
|
||||||
events.remove(q);
|
audit.remove(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(Event event) {
|
public void onEvent(Event event) {
|
||||||
if (includedEvents.contains(event.getType())) {
|
if (includedEvents.contains(event.getEvent())) {
|
||||||
events.insert(convert(event));
|
audit.insert(convert(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ public class MongoEventStoreProvider implements EventStoreProvider {
|
|||||||
static DBObject convert(Event o) {
|
static DBObject convert(Event o) {
|
||||||
BasicDBObject e = new BasicDBObject();
|
BasicDBObject e = new BasicDBObject();
|
||||||
e.put("time", o.getTime());
|
e.put("time", o.getTime());
|
||||||
e.put("type", o.getType().toString());
|
e.put("event", o.getEvent().toString());
|
||||||
e.put("realmId", o.getRealmId());
|
e.put("realmId", o.getRealmId());
|
||||||
e.put("clientId", o.getClientId());
|
e.put("clientId", o.getClientId());
|
||||||
e.put("userId", o.getUserId());
|
e.put("userId", o.getUserId());
|
||||||
@@ -84,7 +84,7 @@ public class MongoEventStoreProvider implements EventStoreProvider {
|
|||||||
static Event convert(BasicDBObject o) {
|
static Event convert(BasicDBObject o) {
|
||||||
Event e = new Event();
|
Event e = new Event();
|
||||||
e.setTime(o.getLong("time"));
|
e.setTime(o.getLong("time"));
|
||||||
e.setType(EventType.valueOf(o.getString("type")));
|
e.setEvent(EventType.valueOf(o.getString("event")));
|
||||||
e.setRealmId(o.getString("realmId"));
|
e.setRealmId(o.getString("realmId"));
|
||||||
e.setClientId(o.getString("clientId"));
|
e.setClientId(o.getString("clientId"));
|
||||||
e.setUserId(o.getString("userId"));
|
e.setUserId(o.getString("userId"));
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package org.keycloak.audit.mongo;
|
||||||
|
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
|
import com.mongodb.WriteConcern;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.audit.AuditProvider;
|
||||||
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
|
import org.keycloak.audit.EventType;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class MongoAuditProviderFactory implements AuditProviderFactory {
|
||||||
|
|
||||||
|
protected static final Logger logger = Logger.getLogger(MongoAuditProviderFactory.class);
|
||||||
|
|
||||||
|
public static final String ID = "mongo";
|
||||||
|
private MongoClient client;
|
||||||
|
private DB db;
|
||||||
|
|
||||||
|
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuditProvider create(ProviderSession providerSession) {
|
||||||
|
return new MongoAuditProvider(db.getCollection("audit"), includedEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
try {
|
||||||
|
String host = config.get("host", ServerAddress.defaultHost());
|
||||||
|
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||||
|
String dbName = config.get("db", "keycloak-audit");
|
||||||
|
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||||
|
|
||||||
|
String user = config.get("user");
|
||||||
|
String password = config.get("password");
|
||||||
|
if (user != null && password != null) {
|
||||||
|
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||||
|
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||||
|
} else {
|
||||||
|
client = new MongoClient(host, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
||||||
|
db = client.getDB(dbName);
|
||||||
|
|
||||||
|
if (clearOnStartup) {
|
||||||
|
db.getCollection("audit").drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.infof("Initialized mongo audit. host: %s, port: %d, db: %s, clearOnStartup: %b", host, port, dbName, clearOnStartup);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] include = config.getArray("include-events");
|
||||||
|
if (include != null) {
|
||||||
|
for (String i : include) {
|
||||||
|
includedEvents.add(EventType.valueOf(i.toUpperCase()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (EventType i : EventType.values()) {
|
||||||
|
includedEvents.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] exclude = config.getArray("exclude-events");
|
||||||
|
if (exclude != null) {
|
||||||
|
for (String e : exclude) {
|
||||||
|
includedEvents.remove(EventType.valueOf(e.toUpperCase()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable → Regular
+9
-8
@@ -1,14 +1,15 @@
|
|||||||
package org.keycloak.events.mongo;
|
package org.keycloak.audit.mongo;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBCollection;
|
import com.mongodb.DBCollection;
|
||||||
import com.mongodb.DBCursor;
|
import com.mongodb.DBCursor;
|
||||||
import org.keycloak.events.Event;
|
import org.keycloak.audit.Event;
|
||||||
import org.keycloak.events.EventQuery;
|
import org.keycloak.audit.EventQuery;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.audit.EventType;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
@@ -26,12 +27,12 @@ public class MongoEventQuery implements EventQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EventQuery type(EventType... types) {
|
public EventQuery event(EventType... events) {
|
||||||
List<String> eventStrings = new LinkedList<String>();
|
List<String> eventStrings = new LinkedList<String>();
|
||||||
for (EventType e : types) {
|
for (EventType e : events) {
|
||||||
eventStrings.add(e.toString());
|
eventStrings.add(e.toString());
|
||||||
}
|
}
|
||||||
query.put("type", new BasicDBObject("$in", eventStrings));
|
query.put("event", new BasicDBObject("$in", eventStrings));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +84,7 @@ public class MongoEventQuery implements EventQuery {
|
|||||||
|
|
||||||
List<Event> events = new LinkedList<Event>();
|
List<Event> events = new LinkedList<Event>();
|
||||||
while (cur.hasNext()) {
|
while (cur.hasNext()) {
|
||||||
events.add(MongoEventStoreProvider.convert((BasicDBObject) cur.next()));
|
events.add(MongoAuditProvider.convert((BasicDBObject) cur.next()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return events;
|
return events;
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.audit.mongo.MongoAuditProviderFactory
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.keycloak.audit.mongo;
|
||||||
|
|
||||||
|
import org.keycloak.audit.tests.AbstractAuditProviderTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class MongoAuditProviderTest extends AbstractAuditProviderTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getProviderId() {
|
||||||
|
return MongoAuditProviderFactory.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,16 +3,16 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<name>Events Parent</name>
|
<name>Audit Parent</name>
|
||||||
<description/>
|
<description/>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-events-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
@@ -21,5 +21,6 @@
|
|||||||
<module>jpa</module>
|
<module>jpa</module>
|
||||||
<module>jboss-logging</module>
|
<module>jboss-logging</module>
|
||||||
<module>mongo</module>
|
<module>mongo</module>
|
||||||
|
<module>tests</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
@@ -3,17 +3,28 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-audit-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-model-sessions-mongo</artifactId>
|
<artifactId>keycloak-audit-tests</artifactId>
|
||||||
<name>Keycloak Model Sessions Mongo</name>
|
<name>Keycloak Audit Tests</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
@@ -23,20 +34,14 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>keycloak-audit-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>keycloak-connections-mongo</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb</groupId>
|
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
package org.keycloak.audit.tests;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.audit.AuditProvider;
|
||||||
|
import org.keycloak.audit.AuditProviderFactory;
|
||||||
|
import org.keycloak.audit.Event;
|
||||||
|
import org.keycloak.audit.EventType;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractAuditProviderTest {
|
||||||
|
|
||||||
|
private ProviderFactory<AuditProvider> factory;
|
||||||
|
private AuditProvider provider;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
String providerId = getProviderId();
|
||||||
|
ServiceLoader<AuditProviderFactory> factories = ServiceLoader.load(AuditProviderFactory.class);
|
||||||
|
for (AuditProviderFactory f : factories) {
|
||||||
|
if (f.getId().equals(providerId)) {
|
||||||
|
factory = f;
|
||||||
|
factory.init(Config.scope("audit", providerId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider = factory.create(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getProviderId();
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
provider.clear();
|
||||||
|
provider.close();
|
||||||
|
factory.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void save() {
|
||||||
|
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void query() {
|
||||||
|
long oldest = System.currentTimeMillis() - 30000;
|
||||||
|
long newest = System.currentTimeMillis() + 30000;
|
||||||
|
|
||||||
|
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(oldest, EventType.LOGIN, "realmId", "clientId2", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
|
||||||
|
|
||||||
|
provider.close();
|
||||||
|
provider = factory.create(null);
|
||||||
|
|
||||||
|
Assert.assertEquals(5, provider.createQuery().client("clientId").getResultList().size());
|
||||||
|
Assert.assertEquals(5, provider.createQuery().realm("realmId").getResultList().size());
|
||||||
|
Assert.assertEquals(4, provider.createQuery().event(EventType.LOGIN).getResultList().size());
|
||||||
|
Assert.assertEquals(6, provider.createQuery().event(EventType.LOGIN, EventType.REGISTER).getResultList().size());
|
||||||
|
Assert.assertEquals(4, provider.createQuery().user("userId").getResultList().size());
|
||||||
|
|
||||||
|
Assert.assertEquals(1, provider.createQuery().user("userId").event(EventType.REGISTER).getResultList().size());
|
||||||
|
|
||||||
|
Assert.assertEquals(2, provider.createQuery().maxResults(2).getResultList().size());
|
||||||
|
Assert.assertEquals(1, provider.createQuery().firstResult(5).getResultList().size());
|
||||||
|
|
||||||
|
Assert.assertEquals(newest, provider.createQuery().maxResults(1).getResultList().get(0).getTime());
|
||||||
|
Assert.assertEquals(oldest, provider.createQuery().firstResult(5).maxResults(1).getResultList().get(0).getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clear() {
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
|
||||||
|
provider.close();
|
||||||
|
provider = factory.create(null);
|
||||||
|
|
||||||
|
provider.clear("realmId");
|
||||||
|
|
||||||
|
Assert.assertEquals(1, provider.createQuery().getResultList().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearOld() {
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||||
|
|
||||||
|
provider.close();
|
||||||
|
provider = factory.create(null);
|
||||||
|
|
||||||
|
provider.clear("realmId", System.currentTimeMillis() - 10000);
|
||||||
|
|
||||||
|
Assert.assertEquals(3, provider.createQuery().getResultList().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event create(EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
|
||||||
|
return create(System.currentTimeMillis(), event, realmId, clientId, userId, ipAddress, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Event create(long time, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
|
||||||
|
Event e = new Event();
|
||||||
|
e.setTime(time);
|
||||||
|
e.setEvent(event);
|
||||||
|
e.setRealmId(realmId);
|
||||||
|
e.setClientId(clientId);
|
||||||
|
e.setUserId(userId);
|
||||||
|
e.setIpAddress(ipAddress);
|
||||||
|
e.setError(error);
|
||||||
|
|
||||||
|
Map<String, String> details = new HashMap<String, String>();
|
||||||
|
details.put("key1", "value1");
|
||||||
|
details.put("key2", "value2");
|
||||||
|
|
||||||
|
e.setDetails(details);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-23
@@ -1,17 +1,16 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-export-import-parent</artifactId>
|
<artifactId>keycloak-authentication-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-export-import-single-file</artifactId>
|
<artifactId>keycloak-authentication-api</artifactId>
|
||||||
<name>Keycloak Export Import To Single File</name>
|
<name>Keycloak Authentication SPI</name>
|
||||||
<description/>
|
<description />
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -26,22 +25,6 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-export-import-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.jackson</groupId>
|
|
||||||
<artifactId>jackson-core-asl</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.jackson</groupId>
|
|
||||||
<artifactId>jackson-mapper-asl</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthProviderConstants {
|
||||||
|
|
||||||
|
// Model is default provider. See AuthenticationProviderModel.DEFAULT_PROVIDER
|
||||||
|
public static final String PROVIDER_NAME_MODEL = "model";
|
||||||
|
public static final String PROVIDER_NAME_EXTERNAL_MODEL = "externalModel";
|
||||||
|
public static final String PROVIDER_NAME_PICKETLINK = "picketlink";
|
||||||
|
|
||||||
|
// Used in external-model provider
|
||||||
|
public static final String EXTERNAL_REALM_ID = "externalRealmId";
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of authentication by AuthenticationProvider
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public enum AuthProviderStatus {
|
||||||
|
|
||||||
|
SUCCESS, INVALID_CREDENTIALS, FAILED
|
||||||
|
|
||||||
|
}
|
||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthUser {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String username;
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
private String providerName;
|
||||||
|
|
||||||
|
public AuthUser(String id, String username, String providerName) {
|
||||||
|
this.id = id;
|
||||||
|
this.username = username;
|
||||||
|
this.providerName = providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setName(String name) {
|
||||||
|
int i = name.lastIndexOf(' ');
|
||||||
|
if (i != -1) {
|
||||||
|
firstName = name.substring(0, i);
|
||||||
|
lastName = name.substring(i + 1);
|
||||||
|
} else {
|
||||||
|
firstName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setName(String firstName, String lastName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProviderName() {
|
||||||
|
return providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser setProviderName(String providerName) {
|
||||||
|
this.providerName = providerName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public interface AuthenticationProvider extends Provider {
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get names of all available configuration options of current provider
|
||||||
|
*
|
||||||
|
* @return options or empty list if no options available
|
||||||
|
*/
|
||||||
|
List<String> getAvailableOptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user by given username or email. Return user instance or null if user doesn't exists in this authentication provider
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* @param configuration
|
||||||
|
* @param username or email
|
||||||
|
* @return found user or null if user with given username doesn't exists
|
||||||
|
* @throws AuthenticationProviderException
|
||||||
|
*/
|
||||||
|
AuthUser getUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to register user with this authentication provider
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* @param configuration
|
||||||
|
* @param username
|
||||||
|
* @return ID of newly created user (For example ID from LDAP)
|
||||||
|
* @throws AuthenticationProviderException if user creation couldn't happen
|
||||||
|
*/
|
||||||
|
String registerUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard Authentication flow
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @return result of authentication, which might eventually encapsulate info about authenticated user and provider which successfully authenticated
|
||||||
|
*/
|
||||||
|
AuthProviderStatus validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update credential
|
||||||
|
*
|
||||||
|
* @param realm
|
||||||
|
* @param configuration
|
||||||
|
* @param username
|
||||||
|
* @param password
|
||||||
|
* @return true if credential has been successfully updated
|
||||||
|
* @throws AuthenticationProviderException
|
||||||
|
*/
|
||||||
|
boolean updateCredential(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthenticationProviderException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 15L;
|
||||||
|
|
||||||
|
protected AuthenticationProviderException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationProviderException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationProviderException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationProviderException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public interface AuthenticationProviderFactory extends ProviderFactory<AuthenticationProvider> {
|
||||||
|
}
|
||||||
+219
@@ -0,0 +1,219 @@
|
|||||||
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.AuthenticationLinkModel;
|
||||||
|
import org.keycloak.models.AuthenticationProviderModel;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access point to authentication SPI. It finds configured and available {@link AuthenticationProvider} instances for current realm
|
||||||
|
* and then delegates method call to them.
|
||||||
|
*
|
||||||
|
* Example of usage: AuthenticationProviderManager.getManager(realm).validateUser("joe", "password");
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthenticationProviderManager {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AuthenticationProviderManager.class);
|
||||||
|
|
||||||
|
private final RealmModel realm;
|
||||||
|
private final Map<String, AuthenticationProvider> delegates;
|
||||||
|
|
||||||
|
public static AuthenticationProviderManager getManager(RealmModel realm, ProviderSession providerSession) {
|
||||||
|
Iterable<AuthenticationProvider> providers = providerSession.getAllProviders(AuthenticationProvider.class);
|
||||||
|
|
||||||
|
Map<String, AuthenticationProvider> providersMap = new HashMap<String, AuthenticationProvider>();
|
||||||
|
for (AuthenticationProvider provider : providers) {
|
||||||
|
providersMap.put(provider.getName(), provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthenticationProviderManager(realm, providersMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationProviderManager(RealmModel realm, Map<String, AuthenticationProvider> delegates) {
|
||||||
|
this.realm = realm;
|
||||||
|
this.delegates = delegates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthUser getUser(String username) {
|
||||||
|
List<AuthenticationProviderModel> authProviderModels = getConfiguredProviderModels(realm);
|
||||||
|
for (AuthenticationProviderModel providerModel : authProviderModels) {
|
||||||
|
AuthenticationProvider delegate = getProvider(providerModel.getProviderName());
|
||||||
|
if (delegate == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AuthUser authUser = delegate.getUser(realm, providerModel.getConfig(), username);
|
||||||
|
if (authUser != null) {
|
||||||
|
logger.debugf("User '%s' found with provider '%s'", username, providerModel.getProviderName());
|
||||||
|
return authUser;
|
||||||
|
}
|
||||||
|
} catch (AuthenticationProviderException ape) {
|
||||||
|
logger.warn(ape.getMessage(), ape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debugf("User '%s' not found with any provider", username);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthProviderStatus validatePassword(UserModel user, String password) {
|
||||||
|
AuthenticationLinkModel authLink = user.getAuthenticationLink();
|
||||||
|
if (authLink == null) {
|
||||||
|
// User not yet linked with any authenticationProvider. Find provider with biggest priority where he is and link
|
||||||
|
AuthUser authUser = getUser(user.getLoginName());
|
||||||
|
authLink = new AuthenticationLinkModel(authUser.getProviderName(), authUser.getId());
|
||||||
|
user.setAuthenticationLink(authLink);
|
||||||
|
logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String providerName = authLink.getAuthProvider();
|
||||||
|
|
||||||
|
AuthenticationProviderModel providerModel = getConfiguredProviderModel(realm, providerName);
|
||||||
|
AuthenticationProvider delegate = getProvider(providerName);
|
||||||
|
if (delegate == null || providerModel == null) {
|
||||||
|
return AuthProviderStatus.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
checkCorrectAuthLink(delegate, providerModel, authLink, user.getLoginName());
|
||||||
|
|
||||||
|
AuthProviderStatus currentResult = delegate.validatePassword(realm, providerModel.getConfig(), user.getLoginName(), password);
|
||||||
|
logger.debugf("Authentication provider '%s' finished with '%s' for authentication of '%s'", delegate.getName(), currentResult.toString(), user.getLoginName());
|
||||||
|
return currentResult;
|
||||||
|
} catch (AuthenticationProviderException ape) {
|
||||||
|
logger.warn(ape.getMessage(), ape);
|
||||||
|
return AuthProviderStatus.FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean updatePassword(UserModel user, String password) throws AuthenticationProviderException {
|
||||||
|
AuthenticationLinkModel authLink = user.getAuthenticationLink();
|
||||||
|
if (authLink == null) {
|
||||||
|
// Find provider with biggest priority where password update is supported. Then register user here and link him
|
||||||
|
List<AuthenticationProviderModel> configuredProviders = getConfiguredProviderModels(realm);
|
||||||
|
for (AuthenticationProviderModel providerModel : configuredProviders) {
|
||||||
|
if (providerModel.isPasswordUpdateSupported()) {
|
||||||
|
AuthenticationProvider delegate = getProvider(providerModel.getProviderName());
|
||||||
|
if (delegate != null) {
|
||||||
|
AuthUser authUser = delegate.getUser(realm, providerModel.getConfig(), user.getLoginName());
|
||||||
|
if (authUser != null) {
|
||||||
|
// Linking existing user supported just for "model" provider. In other cases throw exception
|
||||||
|
if (providerModel.getProviderName().equals(AuthenticationProviderModel.DEFAULT_PROVIDER.getProviderName())) {
|
||||||
|
authLink = new AuthenticationLinkModel(providerModel.getProviderName(), authUser.getId());
|
||||||
|
user.setAuthenticationLink(authLink);
|
||||||
|
logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
|
||||||
|
} else {
|
||||||
|
throw new AuthenticationProviderException("User " + authUser.getUsername() + " exists in provider "
|
||||||
|
+ authUser.getProviderName() + " but is not linked with model user");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String userIdInProvider = delegate.registerUser(realm, providerModel.getConfig(), user.getLoginName());
|
||||||
|
authLink = new AuthenticationLinkModel(providerModel.getProviderName(), userIdInProvider);
|
||||||
|
user.setAuthenticationLink(authLink);
|
||||||
|
logger.infof("User '%s' registered in provider '%s' and linked", user.getLoginName(), providerModel.getProviderName());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authLink == null) {
|
||||||
|
logger.warnf("No providers found where password update is supported for user '%s'", user.getLoginName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String providerName = authLink.getAuthProvider();
|
||||||
|
|
||||||
|
AuthenticationProviderModel providerModel = getConfiguredProviderModel(realm, providerName);
|
||||||
|
if (providerModel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = user.getLoginName();
|
||||||
|
|
||||||
|
// Update just those, which support password update
|
||||||
|
if (providerModel.isPasswordUpdateSupported()) {
|
||||||
|
try {
|
||||||
|
AuthenticationProvider delegate = getProvider(providerName);
|
||||||
|
if (delegate == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCorrectAuthLink(delegate, providerModel, authLink, username);
|
||||||
|
|
||||||
|
if (delegate.updateCredential(realm,providerModel.getConfig(), user.getLoginName(), password)) {
|
||||||
|
logger.debugf("Updated password in authentication provider '%s' for user '%s'", providerName, username);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
logger.warnf("Password not updated in authentication provider '%s' for user '%s'", providerName, username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (AuthenticationProviderException ape) {
|
||||||
|
// Rethrow it to upper layer
|
||||||
|
logger.warn("Failed to update password: " + ape.getMessage());
|
||||||
|
throw ape;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.warnf("Skip password update for authentication provider '%s' for user '%s'", providerName, username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthenticationProvider getProvider(String providerName) {
|
||||||
|
AuthenticationProvider delegate = delegates.get(providerName);
|
||||||
|
if (delegate == null) {
|
||||||
|
logger.warnf("Provider '%s' not available on classpath", providerName);
|
||||||
|
}
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<AuthenticationProviderModel> getConfiguredProviderModels(RealmModel realm) {
|
||||||
|
List<AuthenticationProviderModel> configuredProviders = realm.getAuthenticationProviders();
|
||||||
|
|
||||||
|
// Use model based authentication of current realm by default
|
||||||
|
if (configuredProviders == null || configuredProviders.isEmpty()) {
|
||||||
|
configuredProviders = Collections.EMPTY_LIST;
|
||||||
|
logger.warnf("No authentication providers found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return configuredProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthenticationProviderModel getConfiguredProviderModel(RealmModel realm, String providerName) {
|
||||||
|
List<AuthenticationProviderModel> providers = getConfiguredProviderModels(realm);
|
||||||
|
for (AuthenticationProviderModel provider : providers) {
|
||||||
|
if (providerName.equals(provider.getProviderName())) {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.warnf("Provider '%s' not configured in realm", providerName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if ID of linked AuthUser is same as expected ID from authenticationLink . It should catch the case when for example user "john" was deleted in LDAP
|
||||||
|
// and then user "john" has been created again, but it's actually different user with different ID
|
||||||
|
private void checkCorrectAuthLink(AuthenticationProvider authProvider, AuthenticationProviderModel providerModel,
|
||||||
|
AuthenticationLinkModel authLinkModel, String username) throws AuthenticationProviderException {
|
||||||
|
AuthUser authUser = authProvider.getUser(realm, providerModel.getConfig(), username);
|
||||||
|
if (authUser == null) {
|
||||||
|
throw new AuthenticationProviderException("User " + username + " not found in authentication provider " + providerModel.getProviderName());
|
||||||
|
}
|
||||||
|
String userExternalId = authUser.getId();
|
||||||
|
if (!userExternalId.equals(authLinkModel.getAuthUserId())) {
|
||||||
|
throw new AuthenticationProviderException("ID did not match! ID from provider: " + userExternalId + ", ID from authentication link: " + authLinkModel.getAuthUserId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.connections.jpa;
|
package org.keycloak.authentication;
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
|||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class JpaConnectionSpi implements Spi {
|
public class AuthenticationSpi implements Spi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "connectionsJpa";
|
return "authentication";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends Provider> getProviderClass() {
|
public Class<? extends Provider> getProviderClass() {
|
||||||
return JpaConnectionProvider.class;
|
return AuthenticationProvider.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
return JpaConnectionProviderFactory.class;
|
return AuthenticationProviderFactory.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.authentication.AuthenticationSpi
|
||||||
+24
-16
@@ -1,17 +1,16 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-export-import-parent</artifactId>
|
<artifactId>keycloak-authentication-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-export-import-dir</artifactId>
|
<artifactId>keycloak-authentication-model</artifactId>
|
||||||
<name>Keycloak Export Import To Directory</name>
|
<name>Keycloak Authentication Model Based</name>
|
||||||
<description/>
|
<description />
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -28,19 +27,29 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-export-import-api</artifactId>
|
<artifactId>keycloak-authentication-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.codehaus.jackson</groupId>
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
<artifactId>jackson-core-asl</artifactId>
|
<artifactId>resteasy-jaxrs</artifactId>
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.codehaus.jackson</groupId>
|
|
||||||
<artifactId>jackson-mapper-asl</artifactId>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
@@ -49,7 +58,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserCredentialModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
|
import org.keycloak.authentication.AuthProviderStatus;
|
||||||
|
import org.keycloak.authentication.AuthUser;
|
||||||
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication provider, which delegates calling of all methods to specified realm
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractModelAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AbstractModelAuthenticationProvider.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthUser getUser(RealmModel currentRealm, Map<String, String> config, String username) throws AuthenticationProviderException {
|
||||||
|
RealmModel realm = getRealm(currentRealm, config);
|
||||||
|
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
||||||
|
return user == null ? null : createAuthenticatedUserInstance(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String registerUser(RealmModel currentRealm, Map<String, String> config, String username) throws AuthenticationProviderException {
|
||||||
|
RealmModel realm = getRealm(currentRealm, config);
|
||||||
|
UserModel user = currentRealm.addUser(username);
|
||||||
|
user.setEnabled(true);
|
||||||
|
return user.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthProviderStatus validatePassword(RealmModel currentRealm, Map<String, String> config, String username, String password) throws AuthenticationProviderException {
|
||||||
|
RealmModel realm = getRealm(currentRealm, config);
|
||||||
|
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
||||||
|
|
||||||
|
boolean result = realm.validatePassword(user, password);
|
||||||
|
return result ? AuthProviderStatus.SUCCESS : AuthProviderStatus.INVALID_CREDENTIALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateCredential(RealmModel currentRealm, Map<String, String> config, String username, String password) throws AuthenticationProviderException {
|
||||||
|
RealmModel realm = getRealm(currentRealm, config);
|
||||||
|
|
||||||
|
// Validate password policy
|
||||||
|
String error = realm.getPasswordPolicy().validate(password);
|
||||||
|
if (error != null) {
|
||||||
|
throw new AuthenticationProviderException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserModel user = realm.getUser(username);
|
||||||
|
if (user == null) {
|
||||||
|
logger.warnf("User '%s' doesn't exists. Skip password update", username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserCredentialModel cred = new UserCredentialModel();
|
||||||
|
cred.setType(CredentialRepresentation.PASSWORD);
|
||||||
|
cred.setValue(password);
|
||||||
|
|
||||||
|
user.updateCredential(cred);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) throws AuthenticationProviderException;
|
||||||
|
|
||||||
|
protected AuthUser createAuthenticatedUserInstance(UserModel user) {
|
||||||
|
return new AuthUser(user.getId(), user.getLoginName(), getName())
|
||||||
|
.setName(user.getFirstName(), user.getLastName())
|
||||||
|
.setEmail(user.getEmail());
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderException;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractModelAuthenticationProvider, which delegates authentication operations to different (external) realm
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
|
||||||
|
|
||||||
|
public ExternalModelAuthenticationProvider(ProviderSession providerSession) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAvailableOptions() {
|
||||||
|
return Arrays.asList(AuthProviderConstants.EXTERNAL_REALM_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RealmModel getRealm(RealmModel currentRealm, Map<String, String> configuration) throws AuthenticationProviderException {
|
||||||
|
String realmId = configuration.get(AuthProviderConstants.EXTERNAL_REALM_ID);
|
||||||
|
if (realmId == null) {
|
||||||
|
throw new AuthenticationProviderException("Option '" + AuthProviderConstants.EXTERNAL_REALM_ID + "' not specified in configuration");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This won't be needed when KeycloakSession is available from ProviderSession
|
||||||
|
KeycloakSession session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
|
||||||
|
if (session == null) {
|
||||||
|
throw new AuthenticationProviderException("KeycloakSession not available");
|
||||||
|
}
|
||||||
|
|
||||||
|
RealmModel realm = session.getRealm(realmId);
|
||||||
|
if (realm == null) {
|
||||||
|
throw new AuthenticationProviderException("Realm with id '" + realmId + "' doesn't exists");
|
||||||
|
}
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ExternalModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||||
|
return new ExternalModelAuthenticationProvider(providerSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractModelAuthenticationProvider, which uses current realm to call operations on
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAvailableOptions() {
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) {
|
||||||
|
return currentRealm;
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package org.keycloak.authentication.model;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||||
|
return new ModelAuthenticationProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
org.keycloak.authentication.model.ModelAuthenticationProviderFactory
|
||||||
|
org.keycloak.authentication.model.ExternalModelAuthenticationProviderFactory
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-authentication-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-ldap-federation</artifactId>
|
<artifactId>keycloak-authentication-picketlink</artifactId>
|
||||||
<name>Keycloak LDAP Federation</name>
|
<name>Keycloak Authentication Picketlink Based</name>
|
||||||
<description />
|
<description />
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -25,12 +25,19 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-authentication-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-picketlink-api</artifactId>
|
<artifactId>keycloak-picketlink-api</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.resteasy</groupId>
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
<artifactId>resteasy-jaxrs</artifactId>
|
<artifactId>resteasy-jaxrs</artifactId>
|
||||||
+134
@@ -0,0 +1,134 @@
|
|||||||
|
package org.keycloak.authentication.picketlink;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthProviderStatus;
|
||||||
|
import org.keycloak.authentication.AuthUser;
|
||||||
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderException;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||||
|
import org.picketlink.idm.IdentityManagementException;
|
||||||
|
import org.picketlink.idm.IdentityManager;
|
||||||
|
import org.picketlink.idm.credential.Credentials;
|
||||||
|
import org.picketlink.idm.credential.Password;
|
||||||
|
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
||||||
|
import org.picketlink.idm.model.basic.BasicModel;
|
||||||
|
import org.picketlink.idm.model.basic.User;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AuthenticationProvider, which delegates authentication to picketlink
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class PicketlinkAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(PicketlinkAuthenticationProvider.class);
|
||||||
|
|
||||||
|
private final IdentityManagerProvider identityManagerProvider;
|
||||||
|
|
||||||
|
public PicketlinkAuthenticationProvider(IdentityManagerProvider identityManagerProvider) {
|
||||||
|
this.identityManagerProvider = identityManagerProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAvailableOptions() {
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthUser getUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException {
|
||||||
|
IdentityManager identityManager = getIdentityManager(realm);
|
||||||
|
|
||||||
|
try {
|
||||||
|
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
||||||
|
return picketlinkUser == null ? null : new AuthUser(picketlinkUser.getId(), picketlinkUser.getLoginName(), getName())
|
||||||
|
.setName(picketlinkUser.getFirstName(), picketlinkUser.getLastName())
|
||||||
|
.setEmail(picketlinkUser.getEmail())
|
||||||
|
.setProviderName(getName());
|
||||||
|
} catch (IdentityManagementException ie) {
|
||||||
|
throw convertIDMException(ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String registerUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException {
|
||||||
|
IdentityManager identityManager = getIdentityManager(realm);
|
||||||
|
|
||||||
|
try {
|
||||||
|
User picketlinkUser = new User(username);
|
||||||
|
identityManager.add(picketlinkUser);
|
||||||
|
|
||||||
|
// Hack needed due to ActiveDirectory bug in Picketlink TODO: Remove once https://issues.jboss.org/browse/PLINK-485 fixed and updated in keycloak master
|
||||||
|
picketlinkUser = BasicModel.getUser(identityManager, picketlinkUser.getLoginName());
|
||||||
|
|
||||||
|
return picketlinkUser.getId();
|
||||||
|
} catch (IdentityManagementException ie) {
|
||||||
|
throw convertIDMException(ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthProviderStatus validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
||||||
|
IdentityManager identityManager = getIdentityManager(realm);
|
||||||
|
|
||||||
|
try {
|
||||||
|
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
||||||
|
credential.setUsername(username);
|
||||||
|
credential.setPassword(new Password(password.toCharArray()));
|
||||||
|
identityManager.validateCredentials(credential);
|
||||||
|
if (credential.getStatus() == Credentials.Status.VALID) {
|
||||||
|
return AuthProviderStatus.SUCCESS;
|
||||||
|
} else {
|
||||||
|
return AuthProviderStatus.INVALID_CREDENTIALS;
|
||||||
|
}
|
||||||
|
} catch (IdentityManagementException ie) {
|
||||||
|
throw convertIDMException(ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean updateCredential(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
||||||
|
IdentityManager identityManager = getIdentityManager(realm);
|
||||||
|
|
||||||
|
try {
|
||||||
|
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
||||||
|
if (picketlinkUser == null) {
|
||||||
|
logger.debugf("User '%s' doesn't exists. Skip password update", username);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
identityManager.updateCredential(picketlinkUser, new Password(password.toCharArray()));
|
||||||
|
return true;
|
||||||
|
} catch (IdentityManagementException ie) {
|
||||||
|
throw convertIDMException(ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public IdentityManager getIdentityManager(RealmModel realm) throws AuthenticationProviderException {
|
||||||
|
return identityManagerProvider.getIdentityManager(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AuthenticationProviderException convertIDMException(IdentityManagementException ie) {
|
||||||
|
Throwable realCause = ie;
|
||||||
|
while (realCause.getCause() != null) {
|
||||||
|
realCause = realCause.getCause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the message from the realCause
|
||||||
|
return new AuthenticationProviderException(realCause.getMessage(), ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package org.keycloak.authentication.picketlink;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.authentication.AuthProviderConstants;
|
||||||
|
import org.keycloak.authentication.AuthenticationProvider;
|
||||||
|
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||||
|
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||||
|
import org.keycloak.provider.ProviderSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class PicketlinkAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||||
|
return new PicketlinkAuthenticationProvider(providerSession.getProvider(IdentityManagerProvider.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
org.keycloak.authentication.picketlink.PicketlinkAuthenticationProviderFactory
|
||||||
@@ -5,18 +5,20 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<artifactId>keycloak-federation-parent</artifactId>
|
<artifactId>keycloak-authentication-parent</artifactId>
|
||||||
<name>Keycloak Federation</name>
|
<name>Keycloak Authentication</name>
|
||||||
<description />
|
<description />
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>ldap</module>
|
<module>authentication-api</module>
|
||||||
|
<module>authentication-model</module>
|
||||||
|
<module>authentication-picketlink</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>1.0.5.Final</version>
|
|
||||||
<relativePath>../../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>keycloak-connections-jpa</artifactId>
|
|
||||||
<name>Keycloak Connections JPA</name>
|
|
||||||
<description/>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-core</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
|
||||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-entitymanager</artifactId>
|
|
||||||
<version>${hibernate.entitymanager.version}</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
-26
@@ -1,26 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class DefaultJpaConnectionProvider implements JpaConnectionProvider {
|
|
||||||
|
|
||||||
private final EntityManager em;
|
|
||||||
|
|
||||||
public DefaultJpaConnectionProvider(EntityManager em) {
|
|
||||||
this.em = em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public EntityManager getEntityManager() {
|
|
||||||
return em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
em.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-101
@@ -1,101 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import org.hibernate.ejb.AvailableSettings;
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
|
||||||
import javax.persistence.Persistence;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
|
|
||||||
|
|
||||||
private volatile EntityManagerFactory emf;
|
|
||||||
|
|
||||||
private Config.Scope config;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JpaConnectionProvider create(KeycloakSession session) {
|
|
||||||
lazyInit();
|
|
||||||
|
|
||||||
EntityManager em = emf.createEntityManager();
|
|
||||||
em = PersistenceExceptionConverter.create(em);
|
|
||||||
session.getTransaction().enlist(new JpaKeycloakTransaction(em));
|
|
||||||
return new DefaultJpaConnectionProvider(em);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (emf != null) {
|
|
||||||
emf.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config.Scope config) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void lazyInit() {
|
|
||||||
if (emf == null) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (emf == null) {
|
|
||||||
String unitName = config.get("unitName");
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
|
||||||
|
|
||||||
// Only load config from keycloak-server.json if unitName is not specified
|
|
||||||
if (unitName == null) {
|
|
||||||
unitName = "keycloak-default";
|
|
||||||
|
|
||||||
String dataSource = config.get("dataSource");
|
|
||||||
if (dataSource != null) {
|
|
||||||
if (config.getBoolean("jta", false)) {
|
|
||||||
properties.put(AvailableSettings.JTA_DATASOURCE, dataSource);
|
|
||||||
} else {
|
|
||||||
properties.put(AvailableSettings.NON_JTA_DATASOURCE, dataSource);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
properties.put(AvailableSettings.JDBC_URL, config.get("url"));
|
|
||||||
properties.put(AvailableSettings.JDBC_DRIVER, config.get("driver"));
|
|
||||||
|
|
||||||
String user = config.get("user");
|
|
||||||
if (user != null) {
|
|
||||||
properties.put(AvailableSettings.JDBC_USER, user);
|
|
||||||
}
|
|
||||||
String password = config.get("password");
|
|
||||||
if (password != null) {
|
|
||||||
properties.put(AvailableSettings.JDBC_PASSWORD, password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String driverDialect = config.get("driverDialect");
|
|
||||||
if (driverDialect != null && driverDialect.length() > 0) {
|
|
||||||
properties.put("hibernate.dialect", driverDialect);
|
|
||||||
}
|
|
||||||
|
|
||||||
String databaseSchema = config.get("databaseSchema", "validate");
|
|
||||||
if (databaseSchema != null) {
|
|
||||||
properties.put("hibernate.hbm2ddl.auto", databaseSchema);
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
|
|
||||||
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
|
|
||||||
}
|
|
||||||
|
|
||||||
emf = Persistence.createEntityManagerFactory(unitName, properties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public interface JpaConnectionProvider extends Provider {
|
|
||||||
|
|
||||||
EntityManager getEntityManager();
|
|
||||||
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public interface JpaConnectionProviderFactory extends ProviderFactory<JpaConnectionProvider> {
|
|
||||||
}
|
|
||||||
-53
@@ -1,53 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import javax.persistence.PersistenceException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class JpaKeycloakTransaction implements KeycloakTransaction {
|
|
||||||
|
|
||||||
protected EntityManager em;
|
|
||||||
|
|
||||||
public JpaKeycloakTransaction(EntityManager em) {
|
|
||||||
this.em = em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin() {
|
|
||||||
em.getTransaction().begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commit() {
|
|
||||||
try {
|
|
||||||
em.getTransaction().commit();
|
|
||||||
} catch (PersistenceException e) {
|
|
||||||
throw PersistenceExceptionConverter.convert(e.getCause() != null ? e.getCause() : e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rollback() {
|
|
||||||
em.getTransaction().rollback();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRollbackOnly() {
|
|
||||||
em.getTransaction().setRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getRollbackOnly() {
|
|
||||||
return em.getTransaction().getRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActive() {
|
|
||||||
return em.getTransaction().isActive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
package org.keycloak.connections.jpa;
|
|
||||||
|
|
||||||
import org.hibernate.exception.ConstraintViolationException;
|
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
|
||||||
import org.keycloak.models.ModelException;
|
|
||||||
|
|
||||||
import javax.persistence.EntityExistsException;
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class PersistenceExceptionConverter implements InvocationHandler {
|
|
||||||
|
|
||||||
private EntityManager em;
|
|
||||||
|
|
||||||
public static EntityManager create(EntityManager em) {
|
|
||||||
return (EntityManager) Proxy.newProxyInstance(EntityManager.class.getClassLoader(), new Class[]{EntityManager.class}, new PersistenceExceptionConverter(em));
|
|
||||||
}
|
|
||||||
|
|
||||||
private PersistenceExceptionConverter(EntityManager em) {
|
|
||||||
this.em = em;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
|
||||||
try {
|
|
||||||
return method.invoke(em, args);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw convert(e.getCause());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModelException convert(Throwable t) {
|
|
||||||
if (t.getCause() != null && t.getCause() instanceof ConstraintViolationException) {
|
|
||||||
throw new ModelDuplicateException(t);
|
|
||||||
} if (t instanceof EntityExistsException) {
|
|
||||||
throw new ModelDuplicateException(t);
|
|
||||||
} else {
|
|
||||||
throw new ModelException(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
org.keycloak.connections.jpa.JpaConnectionSpi
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>1.0.5.Final</version>
|
|
||||||
<relativePath>../../pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>keycloak-connections-mongo</artifactId>
|
|
||||||
<name>Keycloak Connections Mongo</name>
|
|
||||||
<description/>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-core</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb</groupId>
|
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.logging</groupId>
|
|
||||||
<artifactId>jboss-logging</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
-111
@@ -1,111 +0,0 @@
|
|||||||
package org.keycloak.connections.mongo;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import com.mongodb.MongoClient;
|
|
||||||
import com.mongodb.MongoCredential;
|
|
||||||
import com.mongodb.ServerAddress;
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
import org.keycloak.Config;
|
|
||||||
import org.keycloak.connections.mongo.api.MongoStore;
|
|
||||||
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
|
|
||||||
import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocationContext;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
|
||||||
|
|
||||||
// TODO Make configurable
|
|
||||||
private String[] entities = new String[]{
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity",
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoUserEntity",
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity",
|
|
||||||
"org.keycloak.models.entities.RequiredCredentialEntity",
|
|
||||||
"org.keycloak.models.entities.CredentialEntity",
|
|
||||||
"org.keycloak.models.entities.SocialLinkEntity",
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity",
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoUsernameLoginFailureEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoUserSessionEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoClientSessionEntity",
|
|
||||||
"org.keycloak.models.entities.UserFederationProviderEntity"
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
|
|
||||||
|
|
||||||
private volatile MongoClient client;
|
|
||||||
|
|
||||||
private MongoStore mongoStore;
|
|
||||||
private DB db;
|
|
||||||
private Config.Scope config;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MongoConnectionProvider create(KeycloakSession session) {
|
|
||||||
lazyInit();
|
|
||||||
|
|
||||||
TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
|
|
||||||
session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
|
|
||||||
return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Config.Scope config) {
|
|
||||||
this.config = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void lazyInit() {
|
|
||||||
if (client == null) {
|
|
||||||
synchronized (this) {
|
|
||||||
if (client == null) {
|
|
||||||
try {
|
|
||||||
String host = config.get("host", ServerAddress.defaultHost());
|
|
||||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
|
||||||
String dbName = config.get("db", "keycloak");
|
|
||||||
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
|
||||||
|
|
||||||
String user = config.get("user");
|
|
||||||
String password = config.get("password");
|
|
||||||
if (user != null && password != null) {
|
|
||||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
|
||||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
|
||||||
} else {
|
|
||||||
client = new MongoClient(host, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db = client.getDB(dbName);
|
|
||||||
|
|
||||||
this.mongoStore = new MongoStoreImpl(db, clearOnStartup, getManagedEntities());
|
|
||||||
|
|
||||||
logger.infof("Initialized mongo model. host: %s, port: %d, db: %s, clearOnStartup: %b", host, port, dbName, clearOnStartup);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class[] getManagedEntities() throws ClassNotFoundException {
|
|
||||||
Class[] entityClasses = new Class[entities.length];
|
|
||||||
for (int i = 0; i < entities.length; i++) {
|
|
||||||
entityClasses[i] = Thread.currentThread().getContextClassLoader().loadClass(entities[i]);
|
|
||||||
}
|
|
||||||
return entityClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
if (client != null) {
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-41
@@ -1,41 +0,0 @@
|
|||||||
package org.keycloak.connections.mongo;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import org.keycloak.connections.mongo.api.MongoStore;
|
|
||||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class DefaultMongoConnectionProvider implements MongoConnectionProvider {
|
|
||||||
|
|
||||||
private DB db;
|
|
||||||
private MongoStore mongoStore;
|
|
||||||
private MongoStoreInvocationContext invocationContext;
|
|
||||||
|
|
||||||
public DefaultMongoConnectionProvider(DB db, MongoStore mongoStore, MongoStoreInvocationContext invocationContext) {
|
|
||||||
this.db = db;
|
|
||||||
this.mongoStore = mongoStore;
|
|
||||||
this.invocationContext = invocationContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DB getDB() {
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MongoStore getMongoStore() {
|
|
||||||
return mongoStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MongoStoreInvocationContext getInvocationContext() {
|
|
||||||
return invocationContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
package org.keycloak.connections.mongo;
|
|
||||||
|
|
||||||
import com.mongodb.DB;
|
|
||||||
import org.keycloak.connections.mongo.api.MongoStore;
|
|
||||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
|
||||||
import org.keycloak.provider.Provider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public interface MongoConnectionProvider extends Provider {
|
|
||||||
|
|
||||||
DB getDB();
|
|
||||||
|
|
||||||
MongoStore getMongoStore();
|
|
||||||
|
|
||||||
MongoStoreInvocationContext getInvocationContext();
|
|
||||||
|
|
||||||
}
|
|
||||||
-9
@@ -1,9 +0,0 @@
|
|||||||
package org.keycloak.connections.mongo;
|
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public interface MongoConnectionProviderFactory extends ProviderFactory<MongoConnectionProvider> {
|
|
||||||
}
|
|
||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
package org.keycloak.connections.mongo;
|
|
||||||
|
|
||||||
import org.keycloak.provider.Provider;
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
import org.keycloak.provider.Spi;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class MongoConnectionSpi implements Spi {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return "connectionsMongo";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends Provider> getProviderClass() {
|
|
||||||
return MongoConnectionProvider.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
|
||||||
return MongoConnectionProviderFactory.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
org.keycloak.connections.mongo.MongoConnectionSpi
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>keycloak-parent</artifactId>
|
|
||||||
<groupId>org.keycloak</groupId>
|
|
||||||
<version>1.0.5.Final</version>
|
|
||||||
</parent>
|
|
||||||
<name>Connections Parent</name>
|
|
||||||
<description/>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>keycloak-connections-pom</artifactId>
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
|
|
||||||
<modules>
|
|
||||||
<module>jpa</module>
|
|
||||||
<module>mongo</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<skip>true</skip>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-11
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.0.5.Final</version>
|
<version>1.0-beta-3</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@@ -13,10 +13,6 @@
|
|||||||
<name>Keycloak Core</name>
|
<name>Keycloak Core</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<timestamp>${maven.build.timestamp}</timestamp>
|
|
||||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bouncycastle</groupId>
|
<groupId>org.bouncycastle</groupId>
|
||||||
@@ -45,12 +41,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ public class AbstractOAuthClient {
|
|||||||
protected String authUrl;
|
protected String authUrl;
|
||||||
protected String codeUrl;
|
protected String codeUrl;
|
||||||
protected String refreshUrl;
|
protected String refreshUrl;
|
||||||
protected boolean relativeUrls;
|
|
||||||
protected String scope;
|
protected String scope;
|
||||||
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
|
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
|
||||||
protected String stateCookiePath;
|
protected String stateCookiePath;
|
||||||
@@ -101,14 +100,6 @@ public class AbstractOAuthClient {
|
|||||||
this.publicClient = publicClient;
|
this.publicClient = publicClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRelativeUrls() {
|
|
||||||
return relativeUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRelativeUrls(boolean relativeUrls) {
|
|
||||||
this.relativeUrls = relativeUrls;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String stripOauthParametersFromRedirect(String uri) {
|
protected String stripOauthParametersFromRedirect(String uri) {
|
||||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
||||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||||
|
|||||||
@@ -16,12 +16,7 @@ public class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getProvider(String spi) {
|
public static String getProvider(String spi) {
|
||||||
String provider = configProvider.getProvider(spi);
|
return configProvider.getProvider(spi);
|
||||||
if (provider == null || provider.trim().equals("")) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scope scope(String... scope) {
|
public static Scope scope(String... scope) {
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package org.keycloak;
|
|
||||||
|
|
||||||
import org.codehaus.jackson.annotate.JsonProperty;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
|
||||||
* @version $Revision: 1 $
|
|
||||||
*/
|
|
||||||
public class Version {
|
|
||||||
public static String VERSION;
|
|
||||||
public static String BUILD_TIME;
|
|
||||||
public static final String UNKNOWN = "UNKNOWN";
|
|
||||||
public static final Version SINGLETON;
|
|
||||||
|
|
||||||
private final String version = VERSION;
|
|
||||||
private final String buildTime = BUILD_TIME;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Properties props = new Properties();
|
|
||||||
InputStream is = Version.class.getResourceAsStream("/keycloak-version.properties");
|
|
||||||
try {
|
|
||||||
props.load(is);
|
|
||||||
VERSION = props.getProperty("version");
|
|
||||||
BUILD_TIME = props.getProperty("build-time");
|
|
||||||
} catch (IOException e) {
|
|
||||||
VERSION=UNKNOWN;
|
|
||||||
BUILD_TIME=UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
SINGLETON = new Version();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonProperty("version")
|
|
||||||
public String getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonProperty("build-time")
|
|
||||||
public String getBuildTime() {
|
|
||||||
return buildTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8,7 +8,6 @@ public interface AdapterConstants {
|
|||||||
|
|
||||||
// URL endpoints
|
// URL endpoints
|
||||||
public static final String K_LOGOUT = "k_logout";
|
public static final String K_LOGOUT = "k_logout";
|
||||||
public static final String K_VERSION = "k_version";
|
|
||||||
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
|
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
|
||||||
public static final String K_GET_USER_STATS = "k_get_user_stats";
|
public static final String K_GET_USER_STATS = "k_get_user_stats";
|
||||||
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
|
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package org.keycloak.enums;
|
|
||||||
|
|
||||||
import org.keycloak.ClientConnection;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public enum SslRequired {
|
|
||||||
|
|
||||||
ALL,
|
|
||||||
EXTERNAL,
|
|
||||||
NONE;
|
|
||||||
|
|
||||||
public boolean isRequired(ClientConnection connection) {
|
|
||||||
return isRequired(connection.getRemoteAddr());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRequired(String address) {
|
|
||||||
switch (this) {
|
|
||||||
case ALL:
|
|
||||||
return true;
|
|
||||||
case NONE:
|
|
||||||
return false;
|
|
||||||
case EXTERNAL:
|
|
||||||
return !isLocal(address);
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLocal(String remoteAddress) {
|
|
||||||
try {
|
|
||||||
InetAddress inetAddress = InetAddress.getByName(remoteAddress);
|
|
||||||
return inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isSiteLocalAddress();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File renamed without changes.
+1
-2
@@ -1,14 +1,13 @@
|
|||||||
package org.keycloak.provider;
|
package org.keycloak.provider;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface ProviderFactory<T extends Provider> {
|
public interface ProviderFactory<T extends Provider> {
|
||||||
|
|
||||||
public T create(KeycloakSession session);
|
public T create(ProviderSession providerSession);
|
||||||
|
|
||||||
public void init(Config.Scope config);
|
public void init(Config.Scope config);
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface ProviderSession {
|
||||||
|
|
||||||
|
<T extends Provider> T getProvider(Class<T> clazz);
|
||||||
|
|
||||||
|
<T extends Provider> T getProvider(Class<T> clazz, String id);
|
||||||
|
|
||||||
|
<T extends Provider> Set<String> listProviderIds(Class<T> clazz);
|
||||||
|
|
||||||
|
<T extends Provider> Set<T> getAllProviders(Class<T> clazz);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.keycloak.provider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public interface ProviderSessionFactory {
|
||||||
|
|
||||||
|
ProviderSession createSession();
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
}
|
||||||
File renamed without changes.
@@ -1,47 +0,0 @@
|
|||||||
package org.keycloak.representations;
|
|
||||||
|
|
||||||
import org.keycloak.util.Time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
|
||||||
*/
|
|
||||||
public class PasswordToken {
|
|
||||||
|
|
||||||
private String realm;
|
|
||||||
private String user;
|
|
||||||
private int timestamp;
|
|
||||||
|
|
||||||
public PasswordToken() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public PasswordToken(String realm, String user) {
|
|
||||||
this.realm = realm;
|
|
||||||
this.user = user;
|
|
||||||
this.timestamp = Time.currentTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRealm() {
|
|
||||||
return realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRealm(String realm) {
|
|
||||||
this.realm = realm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUser() {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(String user) {
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTimestamp() {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimestamp(int timestamp) {
|
|
||||||
this.timestamp = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
|||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
|
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||||
"resource", "credentials",
|
"resource", "credentials",
|
||||||
"use-resource-role-mappings",
|
"use-resource-role-mappings",
|
||||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import java.util.Map;
|
|||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
|
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||||
"resource", "public-client", "credentials",
|
"resource", "public-client", "credentials",
|
||||||
"use-resource-role-mappings",
|
"use-resource-role-mappings",
|
||||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||||
|
|||||||
+7
-7
@@ -9,7 +9,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
|||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required"})
|
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required"})
|
||||||
public class BaseRealmConfig {
|
public class BaseRealmConfig {
|
||||||
@JsonProperty("realm")
|
@JsonProperty("realm")
|
||||||
protected String realm;
|
protected String realm;
|
||||||
@@ -17,15 +17,15 @@ public class BaseRealmConfig {
|
|||||||
protected String realmKey;
|
protected String realmKey;
|
||||||
@JsonProperty("auth-server-url")
|
@JsonProperty("auth-server-url")
|
||||||
protected String authServerUrl;
|
protected String authServerUrl;
|
||||||
@JsonProperty("ssl-required")
|
@JsonProperty("ssl-not-required")
|
||||||
protected String sslRequired;
|
protected boolean sslNotRequired;
|
||||||
|
|
||||||
public String getSslRequired() {
|
public boolean isSslNotRequired() {
|
||||||
return sslRequired;
|
return sslNotRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSslRequired(String sslRequired) {
|
public void setSslNotRequired(boolean sslNotRequired) {
|
||||||
this.sslRequired = sslRequired;
|
this.sslNotRequired = sslNotRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRealm() {
|
public String getRealm() {
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ public class ApplicationRepresentation {
|
|||||||
protected Integer notBefore;
|
protected Integer notBefore;
|
||||||
protected Boolean bearerOnly;
|
protected Boolean bearerOnly;
|
||||||
protected Boolean publicClient;
|
protected Boolean publicClient;
|
||||||
protected Boolean fullScopeAllowed;
|
|
||||||
|
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
@@ -135,12 +134,4 @@ public class ApplicationRepresentation {
|
|||||||
public void setPublicClient(Boolean publicClient) {
|
public void setPublicClient(Boolean publicClient) {
|
||||||
this.publicClient = publicClient;
|
this.publicClient = publicClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isFullScopeAllowed() {
|
|
||||||
return fullScopeAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
|
||||||
this.fullScopeAllowed = fullScopeAllowed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package org.keycloak.representations.idm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthenticationLinkRepresentation {
|
||||||
|
|
||||||
|
private String authProvider;
|
||||||
|
private String authUserId;
|
||||||
|
|
||||||
|
public String getAuthProvider() {
|
||||||
|
return authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthProvider(String authProvider) {
|
||||||
|
this.authProvider = authProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthUserId() {
|
||||||
|
return authUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthUserId(String authUserId) {
|
||||||
|
this.authUserId = authUserId;
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package org.keycloak.representations.idm;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AuthenticationProviderRepresentation {
|
||||||
|
|
||||||
|
private String providerName;
|
||||||
|
private boolean passwordUpdateSupported = true;
|
||||||
|
private Map<String, String> config;
|
||||||
|
|
||||||
|
public String getProviderName() {
|
||||||
|
return providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProviderName(String providerName) {
|
||||||
|
this.providerName = providerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPasswordUpdateSupported() {
|
||||||
|
return passwordUpdateSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordUpdateSupported(boolean passwordUpdateSupported) {
|
||||||
|
this.passwordUpdateSupported = passwordUpdateSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getConfig() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfig(Map<String, String> config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -95,40 +95,4 @@ public class ClaimRepresentation {
|
|||||||
public void setPhone(boolean phone) {
|
public void setPhone(boolean phone) {
|
||||||
this.phone = phone;
|
this.phone = phone;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
|
|
||||||
ClaimRepresentation that = (ClaimRepresentation) o;
|
|
||||||
|
|
||||||
if (address != that.address) return false;
|
|
||||||
if (email != that.email) return false;
|
|
||||||
if (gender != that.gender) return false;
|
|
||||||
if (locale != that.locale) return false;
|
|
||||||
if (name != that.name) return false;
|
|
||||||
if (phone != that.phone) return false;
|
|
||||||
if (picture != that.picture) return false;
|
|
||||||
if (profile != that.profile) return false;
|
|
||||||
if (username != that.username) return false;
|
|
||||||
if (website != that.website) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = (name ? 1 : 0);
|
|
||||||
result = 31 * result + (username ? 1 : 0);
|
|
||||||
result = 31 * result + (profile ? 1 : 0);
|
|
||||||
result = 31 * result + (picture ? 1 : 0);
|
|
||||||
result = 31 * result + (website ? 1 : 0);
|
|
||||||
result = 31 * result + (email ? 1 : 0);
|
|
||||||
result = 31 * result + (gender ? 1 : 0);
|
|
||||||
result = 31 * result + (locale ? 1 : 0);
|
|
||||||
result = 31 * result + (address ? 1 : 0);
|
|
||||||
result = 31 * result + (phone ? 1 : 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loaded 100 of 1102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user