Compare commits
333
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b071b83aa | ||
|
|
eef6e94923 | ||
|
|
f6d50245ac | ||
|
|
f3940bf78c | ||
|
|
62bcf17a1e | ||
|
|
44f9b28618 | ||
|
|
9ec0409a46 | ||
|
|
cd5e191b18 | ||
|
|
a14b3753da | ||
|
|
41b8701d51 | ||
|
|
d84e7eb38b | ||
|
|
d40b256557 | ||
|
|
5304e197e5 | ||
|
|
623e28b9c2 | ||
|
|
274bc4e33a | ||
|
|
42b44ed3b0 | ||
|
|
b0c99e6111 | ||
|
|
fe73feee34 | ||
|
|
629d3ce4aa | ||
|
|
ed6c290bbc | ||
|
|
9dde3f60d6 | ||
|
|
1bcc8c9110 | ||
|
|
bb132e1aa0 | ||
|
|
5e4b843eb7 | ||
|
|
85cc63c7ce | ||
|
|
a697f4bd41 | ||
|
|
7e03c74bc3 | ||
|
|
67f7bcec99 | ||
|
|
267b80c2fa | ||
|
|
66e848710e | ||
|
|
93f48ecb6c | ||
|
|
ecace349f5 | ||
|
|
4a5b313816 | ||
|
|
c79506a34f | ||
|
|
5e97051c07 | ||
|
|
562aa24ebf | ||
|
|
4a66687304 | ||
|
|
42c2066fd8 | ||
|
|
161b3293dc | ||
|
|
a9608904d0 | ||
|
|
1b9358c4c6 | ||
|
|
70ff6c7209 | ||
|
|
3133e30265 | ||
|
|
d0c2e80949 | ||
|
|
89e1937501 | ||
|
|
c05f83c9b3 | ||
|
|
f2e97ff9d6 | ||
|
|
ca4ed6d528 | ||
|
|
8006ea073b | ||
|
|
f8b4a91fa8 | ||
|
|
e17d6c81f9 | ||
|
|
f77de41b2e | ||
|
|
c12577e886 | ||
|
|
5daec20a6e | ||
|
|
6d3aaa0560 | ||
|
|
2e11e71453 | ||
|
|
fb561b8fd6 | ||
|
|
a26ac1758c | ||
|
|
ef60e17641 | ||
|
|
53943f8246 | ||
|
|
0b8b31a3ea | ||
|
|
6f3132eafd | ||
|
|
dcb5717154 | ||
|
|
bfdb8d4e2d | ||
|
|
91fced3b87 | ||
|
|
825c475c7f | ||
|
|
89471b7db1 | ||
|
|
95233af485 | ||
|
|
fc37398235 | ||
|
|
16ea18370d | ||
|
|
1049bca433 | ||
|
|
364174fb7e | ||
|
|
5352872b4b | ||
|
|
bd0887d18e | ||
|
|
9a5f42039d | ||
|
|
ce8dd136bd | ||
|
|
1be2bff95f | ||
|
|
485ca9c90f | ||
|
|
811cfd52c9 | ||
|
|
5c1807eb2d | ||
|
|
7c15a70f53 | ||
|
|
c9c525e942 | ||
|
|
5d141d4d8a | ||
|
|
e96d6f0dfd | ||
|
|
423dc1b8a7 | ||
|
|
ab080dcdd8 | ||
|
|
6f173d4554 | ||
|
|
649a40f58c | ||
|
|
d06668d39b | ||
|
|
b23463a1d2 | ||
|
|
7f81032577 | ||
|
|
280cbf2174 | ||
|
|
228bb297c2 | ||
|
|
f96e59d085 | ||
|
|
86300e7e86 | ||
|
|
5dea07793b | ||
|
|
5e51204114 | ||
|
|
4c0751c1a0 | ||
|
|
ec1434c65e | ||
|
|
aa7bbeb11b | ||
|
|
88a39dbaf7 | ||
|
|
52920119bd | ||
|
|
47ac358bb6 | ||
|
|
62aa2d7f65 | ||
|
|
557de7690e | ||
|
|
4c8da3d614 | ||
|
|
3f539c6d5c | ||
|
|
5b1d67f17d | ||
|
|
e3e32982a0 | ||
|
|
b771cd30e7 | ||
|
|
ac29db51e5 | ||
|
|
6e3770f04a | ||
|
|
d0a3a04d34 | ||
|
|
c5662020d8 | ||
|
|
fea0d1af66 | ||
|
|
30cd28d288 | ||
|
|
c475721dab | ||
|
|
839069ca15 | ||
|
|
09860f1ee1 | ||
|
|
a1b6378bef | ||
|
|
3530fa6259 | ||
|
|
d22afd78e6 | ||
|
|
f1986093e6 | ||
|
|
6c5477bc02 | ||
|
|
ae6fd458e8 | ||
|
|
cdda48d895 | ||
|
|
556314ae15 | ||
|
|
a2845fa0b4 | ||
|
|
8c4a3374d3 | ||
|
|
b97106b750 | ||
|
|
7907abd206 | ||
|
|
090871f8b9 | ||
|
|
0baf12c0ef | ||
|
|
1599371ee5 | ||
|
|
3bc27ef366 | ||
|
|
d5c5cc8321 | ||
|
|
aea00fc574 | ||
|
|
e9dc8b2460 | ||
|
|
eaed199b20 | ||
|
|
f7fcefc11c | ||
|
|
1f0dcbddbe | ||
|
|
9af0743883 | ||
|
|
7d4863783c | ||
|
|
d87718f768 | ||
|
|
c7ba6159b5 | ||
|
|
b43909aff1 | ||
|
|
87d9a5422d | ||
|
|
44937d33ad | ||
|
|
b561080f3a | ||
|
|
d905ce12e3 | ||
|
|
7040bd1c51 | ||
|
|
cd91a29a89 | ||
|
|
b1b452815a | ||
|
|
59d66dd20e | ||
|
|
0763d0d9d6 | ||
|
|
8c8c44e50f | ||
|
|
14b1941454 | ||
|
|
e52811ac28 | ||
|
|
4f3a980f8b | ||
|
|
05a1fc1ded | ||
|
|
ff74d1ddc0 | ||
|
|
31b0f5543f | ||
|
|
39c0be5d99 | ||
|
|
fb18789b05 | ||
|
|
bcbf5da4b8 | ||
|
|
e1b9dfe65d | ||
|
|
52f86f2293 | ||
|
|
e413694cf5 | ||
|
|
20ce36dc64 | ||
|
|
a3c982a630 | ||
|
|
e0542b5260 | ||
|
|
7c7025a83d | ||
|
|
3e6a1f47ec | ||
|
|
32703d19a0 | ||
|
|
cdc6588ac1 | ||
|
|
57aea9b51c | ||
|
|
a2171bf777 | ||
|
|
b9d0f64f74 | ||
|
|
55d614fce8 | ||
|
|
46d118207a | ||
|
|
3bfe3d256e | ||
|
|
b50ab14a0a | ||
|
|
08c58cf2f2 | ||
|
|
d26543360b | ||
|
|
fb18004c1d | ||
|
|
49fb452a79 | ||
|
|
55bd889a0f | ||
|
|
269a0dbec1 | ||
|
|
cf51db88e7 | ||
|
|
fc0889cd2e | ||
|
|
b3b480c25f | ||
|
|
892fa04130 | ||
|
|
8d3e51c236 | ||
|
|
fd9d2ba4d5 | ||
|
|
75bc633a33 | ||
|
|
3fdb22cb05 | ||
|
|
f51ba1cb8a | ||
|
|
688f4a07a3 | ||
|
|
6c7d0f27a7 | ||
|
|
1e5ca3062c | ||
|
|
ca97e7ba35 | ||
|
|
e99afec7ec | ||
|
|
a23853a6bc | ||
|
|
7c8edb5d11 | ||
|
|
83ad045410 | ||
|
|
e5d5276135 | ||
|
|
6f38a02aaa | ||
|
|
5dd84f1d9a | ||
|
|
30147ce25a | ||
|
|
dd011f043d | ||
|
|
7dec0319b6 | ||
|
|
06c14df0f3 | ||
|
|
041d0be990 | ||
|
|
f6a76e673c | ||
|
|
47f361a4ab | ||
|
|
6e7924da76 | ||
|
|
df1a0c03b6 | ||
|
|
971bea8a24 | ||
|
|
c8f0a1ab5a | ||
|
|
0ae9ac0848 | ||
|
|
3dd52e8b28 | ||
|
|
0f6915c615 | ||
|
|
74cd23b331 | ||
|
|
cc17895ef3 | ||
|
|
09ada81b27 | ||
|
|
75e0fa87c3 | ||
|
|
6628e226e4 | ||
|
|
89d47a392b | ||
|
|
c38abb2cfe | ||
|
|
faf18dfdfd | ||
|
|
2dc32fb8c9 | ||
|
|
2ec029e8e0 | ||
|
|
80904209b3 | ||
|
|
8b1483d7ef | ||
|
|
bbeff1ef22 | ||
|
|
aac3c2e0ee | ||
|
|
a240a00983 | ||
|
|
c86a6ba3f3 | ||
|
|
bc301baa1f | ||
|
|
edbf26f007 | ||
|
|
5dca2a3588 | ||
|
|
cf5a7d228b | ||
|
|
f7a7c3ca7b | ||
|
|
28fcdf0b8f | ||
|
|
c38ec33881 | ||
|
|
cfee00d4c5 | ||
|
|
46bf0d78fa | ||
|
|
a14be592de | ||
|
|
29691a3167 | ||
|
|
517a2b99d7 | ||
|
|
edf73af508 | ||
|
|
4a5ea08a2a | ||
|
|
7b86cca649 | ||
|
|
c77b7cd7d6 | ||
|
|
6b0a87c57a | ||
|
|
b1c331c5f3 | ||
|
|
7ae342452e | ||
|
|
4438aa6606 | ||
|
|
8cd8472003 | ||
|
|
687aa78567 | ||
|
|
8419e5883d | ||
|
|
4bac0474c6 | ||
|
|
f0b66a2241 | ||
|
|
51b71e8f20 | ||
|
|
8615515b9a | ||
|
|
10cf486d26 | ||
|
|
abb1647672 | ||
|
|
114c1b95fa | ||
|
|
4e88bbc811 | ||
|
|
504a41aec4 | ||
|
|
e9bf1ef618 | ||
|
|
9d6e450c05 | ||
|
|
fb7e95f1e4 | ||
|
|
f95418dfc9 | ||
|
|
94be235a0f | ||
|
|
100de5a55e | ||
|
|
26570de4cd | ||
|
|
7c97e02715 | ||
|
|
e73bdf9d8c | ||
|
|
8d1ff1d49c | ||
|
|
de770d2881 | ||
|
|
7f96770089 | ||
|
|
3f83538fc1 | ||
|
|
3040f4e89f | ||
|
|
c57c264d91 | ||
|
|
8ba7559cac | ||
|
|
c4d5a4138c | ||
|
|
d699404ce7 | ||
|
|
ee79747cb6 | ||
|
|
5cb6c4e77c | ||
|
|
05638a8953 | ||
|
|
48f7efc97f | ||
|
|
9aa6b4cbfa | ||
|
|
cae0a7628d | ||
|
|
82e29dfcb3 | ||
|
|
ad94b94833 | ||
|
|
687e497455 | ||
|
|
67f31648a6 | ||
|
|
d332851a75 | ||
|
|
4a18a32cfc | ||
|
|
428cd54a81 | ||
|
|
dc4e8603d7 | ||
|
|
b96f8aef6d | ||
|
|
dc50c312cb | ||
|
|
1f12a2d67b | ||
|
|
a2bef7dbbe | ||
|
|
c6af13c8cc | ||
|
|
5be5f6475f | ||
|
|
5673fb34b1 | ||
|
|
5214fe2a55 | ||
|
|
76db33829b | ||
|
|
746da8f270 | ||
|
|
f8667cdb38 | ||
|
|
1ec4fe921d | ||
|
|
915701106c | ||
|
|
2309e6f040 | ||
|
|
839d823edd | ||
|
|
99e6f0edad | ||
|
|
bb138bd6e4 | ||
|
|
32a19563a5 | ||
|
|
3b65127399 | ||
|
|
c17a5823e9 | ||
|
|
c9e88c944a | ||
|
|
b93cf4868c | ||
|
|
53ac88ca26 | ||
|
|
aff32f69bb | ||
|
|
4fcf11d0db | ||
|
|
e04af84ac0 | ||
|
|
9e4086e501 | ||
|
|
5764ad84e9 | ||
|
|
f3fde4a8df | ||
|
|
983ccdd121 | ||
|
|
73ed22c52c |
No files matched your search
@@ -1,4 +1,35 @@
|
||||
keycloak
|
||||
========
|
||||
|
||||
SSO Service for web apps and REST services.
|
||||
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
|
||||
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,2 +0,0 @@
|
||||
org.keycloak.audit.AuditProviderSpi
|
||||
org.keycloak.audit.AuditListenerSpi
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.email.EmailAuditListenerFactory
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.log.JBossLoggingAuditListenerFactory
|
||||
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.jpa.JpaAuditProviderFactory
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.mongo.MongoAuditProviderFactory
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Regular → Executable
+5
-6
@@ -9,7 +9,6 @@ import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@@ -69,11 +68,6 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
||||
properties.put(AvailableSettings.JDBC_URL, config.get("url"));
|
||||
properties.put(AvailableSettings.JDBC_DRIVER, config.get("driver"));
|
||||
|
||||
String driverDialect = config.get("driverDialect");
|
||||
if (driverDialect != null && driverDialect.length() > 0) {
|
||||
properties.put("hibernate.dialect", driverDialect);
|
||||
}
|
||||
|
||||
String user = config.get("user");
|
||||
if (user != null) {
|
||||
properties.put(AvailableSettings.JDBC_USER, user);
|
||||
@@ -84,6 +78,11 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<class>org.keycloak.models.jpa.entities.CredentialEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RealmEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RealmAttributeEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RoleEntity</class>
|
||||
@@ -24,7 +25,7 @@
|
||||
<class>org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity</class>
|
||||
|
||||
<!-- JpaAuditProvider -->
|
||||
<class>org.keycloak.audit.jpa.EventEntity</class>
|
||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+2
@@ -42,11 +42,13 @@ public class MongoKeycloakTransaction implements KeycloakTransaction {
|
||||
} catch (MongoException e) {
|
||||
throw MongoStoreImpl.convertException(e);
|
||||
}
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
invocationContext.rollback();
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
<name>Connections Parent</name>
|
||||
<description/>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+11
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -13,6 +13,10 @@
|
||||
<name>Keycloak Core</name>
|
||||
<description/>
|
||||
|
||||
<properties>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
@@ -41,6 +45,12 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
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,6 +8,7 @@ public interface AdapterConstants {
|
||||
|
||||
// URL endpoints
|
||||
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_GET_USER_STATS = "k_get_user_stats";
|
||||
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package org.keycloak.representations.idm;
|
||||
public class CredentialRepresentation {
|
||||
public static final String SECRET = "secret";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String PASSWORD_TOKEN = "password-token";
|
||||
public static final String TOTP = "totp";
|
||||
public static final String CLIENT_CERT = "cert";
|
||||
|
||||
@@ -20,6 +21,8 @@ public class CredentialRepresentation {
|
||||
protected String hashedSaltedValue;
|
||||
protected String salt;
|
||||
protected Integer hashIterations;
|
||||
// only used when updating a credential. Might set required action
|
||||
protected boolean temporary;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
@@ -68,4 +71,12 @@ public class CredentialRepresentation {
|
||||
public void setHashIterations(Integer hashIterations) {
|
||||
this.hashIterations = hashIterations;
|
||||
}
|
||||
|
||||
public boolean isTemporary() {
|
||||
return temporary;
|
||||
}
|
||||
|
||||
public void setTemporary(boolean temporary) {
|
||||
this.temporary = temporary;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RealmAuditRepresentation {
|
||||
protected boolean auditEnabled;
|
||||
protected Long auditExpiration;
|
||||
protected List<String> auditListeners;
|
||||
|
||||
public boolean isAuditEnabled() {
|
||||
return auditEnabled;
|
||||
}
|
||||
|
||||
public void setAuditEnabled(boolean auditEnabled) {
|
||||
this.auditEnabled = auditEnabled;
|
||||
}
|
||||
|
||||
public Long getAuditExpiration() {
|
||||
return auditExpiration;
|
||||
}
|
||||
|
||||
public void setAuditExpiration(Long auditExpiration) {
|
||||
this.auditExpiration = auditExpiration;
|
||||
}
|
||||
|
||||
public List<String> getAuditListeners() {
|
||||
return auditListeners;
|
||||
}
|
||||
|
||||
public void setAuditListeners(List<String> auditListeners) {
|
||||
this.auditListeners = auditListeners;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RealmEventsConfigRepresentation {
|
||||
protected boolean eventsEnabled;
|
||||
protected Long eventsExpiration;
|
||||
protected List<String> eventsListeners;
|
||||
|
||||
public boolean isEventsEnabled() {
|
||||
return eventsEnabled;
|
||||
}
|
||||
|
||||
public void setEventsEnabled(boolean eventsEnabled) {
|
||||
this.eventsEnabled = eventsEnabled;
|
||||
}
|
||||
|
||||
public Long getEventsExpiration() {
|
||||
return eventsExpiration;
|
||||
}
|
||||
|
||||
public void setEventsExpiration(Long eventsExpiration) {
|
||||
this.eventsExpiration = eventsExpiration;
|
||||
}
|
||||
|
||||
public List<String> getEventsListeners() {
|
||||
return eventsListeners;
|
||||
}
|
||||
|
||||
public void setEventsListeners(List<String> eventsListeners) {
|
||||
this.eventsListeners = eventsListeners;
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,7 @@ public class RealmRepresentation {
|
||||
protected Map<String, List<ScopeMappingRepresentation>> applicationScopeMappings;
|
||||
protected List<ApplicationRepresentation> applications;
|
||||
protected List<OAuthClientRepresentation> oauthClients;
|
||||
protected Map<String, String> browserSecurityHeaders;
|
||||
protected Map<String, String> socialProviders;
|
||||
protected Map<String, String> smtpServer;
|
||||
protected List<UserFederationProviderRepresentation> userFederationProviders;
|
||||
@@ -59,9 +60,9 @@ public class RealmRepresentation {
|
||||
protected String accountTheme;
|
||||
protected String adminTheme;
|
||||
protected String emailTheme;
|
||||
protected boolean auditEnabled;
|
||||
protected long auditExpiration;
|
||||
protected List<String> auditListeners;
|
||||
protected boolean eventsEnabled;
|
||||
protected long eventsExpiration;
|
||||
protected List<String> eventsListeners;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -291,6 +292,14 @@ public class RealmRepresentation {
|
||||
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
|
||||
}
|
||||
|
||||
public Map<String, String> getBrowserSecurityHeaders() {
|
||||
return browserSecurityHeaders;
|
||||
}
|
||||
|
||||
public void setBrowserSecurityHeaders(Map<String, String> browserSecurityHeaders) {
|
||||
this.browserSecurityHeaders = browserSecurityHeaders;
|
||||
}
|
||||
|
||||
public Map<String, String> getSocialProviders() {
|
||||
return socialProviders;
|
||||
}
|
||||
@@ -427,28 +436,28 @@ public class RealmRepresentation {
|
||||
this.failureFactor = failureFactor;
|
||||
}
|
||||
|
||||
public boolean isAuditEnabled() {
|
||||
return auditEnabled;
|
||||
public boolean isEventsEnabled() {
|
||||
return eventsEnabled;
|
||||
}
|
||||
|
||||
public void setAuditEnabled(boolean auditEnabled) {
|
||||
this.auditEnabled = auditEnabled;
|
||||
public void setEventsEnabled(boolean eventsEnabled) {
|
||||
this.eventsEnabled = eventsEnabled;
|
||||
}
|
||||
|
||||
public long getAuditExpiration() {
|
||||
return auditExpiration;
|
||||
public long getEventsExpiration() {
|
||||
return eventsExpiration;
|
||||
}
|
||||
|
||||
public void setAuditExpiration(long auditExpiration) {
|
||||
this.auditExpiration = auditExpiration;
|
||||
public void setEventsExpiration(long eventsExpiration) {
|
||||
this.eventsExpiration = eventsExpiration;
|
||||
}
|
||||
|
||||
public List<String> getAuditListeners() {
|
||||
return auditListeners;
|
||||
public List<String> getEventsListeners() {
|
||||
return eventsListeners;
|
||||
}
|
||||
|
||||
public void setAuditListeners(List<String> auditListeners) {
|
||||
this.auditListeners = auditListeners;
|
||||
public void setEventsListeners(List<String> eventsListeners) {
|
||||
this.eventsListeners = eventsListeners;
|
||||
}
|
||||
|
||||
public List<UserFederationProviderRepresentation> getUserFederationProviders() {
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
||||
+27
@@ -12,6 +12,9 @@ public class UserFederationProviderRepresentation {
|
||||
private String providerName;
|
||||
private Map<String, String> config;
|
||||
private int priority;
|
||||
private int fullSyncPeriod;
|
||||
private int changedSyncPeriod;
|
||||
private int lastSync;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -54,6 +57,30 @@ public class UserFederationProviderRepresentation {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public int getFullSyncPeriod() {
|
||||
return fullSyncPeriod;
|
||||
}
|
||||
|
||||
public void setFullSyncPeriod(int fullSyncPeriod) {
|
||||
this.fullSyncPeriod = fullSyncPeriod;
|
||||
}
|
||||
|
||||
public int getChangedSyncPeriod() {
|
||||
return changedSyncPeriod;
|
||||
}
|
||||
|
||||
public void setChangedSyncPeriod(int changedSyncPeriod) {
|
||||
this.changedSyncPeriod = changedSyncPeriod;
|
||||
}
|
||||
|
||||
public int getLastSync() {
|
||||
return lastSync;
|
||||
}
|
||||
|
||||
public void setLastSync(int lastSync) {
|
||||
this.lastSync = lastSync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
Regular → Executable
+1
-1
@@ -21,8 +21,8 @@
|
||||
*/
|
||||
package org.keycloak.util;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* A utility class for replacing properties in strings.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.keycloak.util;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class UriUtils {
|
||||
|
||||
private static final Pattern originPattern = Pattern.compile("(http://|https://)[\\w-]+(\\.[\\w-]+)*(:[\\d]{2,5})?");
|
||||
|
||||
public static String getOrigin(URI uri) {
|
||||
return getOrigin(uri.toString());
|
||||
}
|
||||
|
||||
public static String getOrigin(String uri) {
|
||||
String u = uri.toString();
|
||||
return u.substring(0, u.indexOf('/', 8));
|
||||
}
|
||||
|
||||
public static boolean isOrigin(String url) {
|
||||
return originPattern.matcher(url).matches();
|
||||
}
|
||||
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
version=${project.version}
|
||||
build-time=${timestamp}
|
||||
@@ -206,7 +206,6 @@ public class RSAVerifierTest {
|
||||
v = verifySkeletonKeyToken(encoded);
|
||||
Assert.fail();
|
||||
} catch (VerificationException ignored) {
|
||||
System.out.println(ignored.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +224,6 @@ public class RSAVerifierTest {
|
||||
try {
|
||||
v = verifySkeletonKeyToken(encoded);
|
||||
} catch (VerificationException ignored) {
|
||||
System.out.println(ignored.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@ public class SkeletonKeyTokenTest {
|
||||
token.addAccess("bar").addRole("user");
|
||||
|
||||
String json = JsonSerialization.writeValueAsString(token);
|
||||
System.out.println(json);
|
||||
|
||||
token = JsonSerialization.readValue(json, AccessToken.class);
|
||||
Assert.assertEquals("111", token.getId());
|
||||
AccessToken.Access foo = token.getResourceAccess("foo");
|
||||
@@ -47,8 +45,6 @@ public class SkeletonKeyTokenTest {
|
||||
.jsonContent(token)
|
||||
.rsa256(keyPair.getPrivate());
|
||||
|
||||
System.out.println(encoded);
|
||||
|
||||
JWSInput input = new JWSInput(encoded);
|
||||
|
||||
token = input.readJsonContent(AccessToken.class);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.keycloak.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class UriUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testOrigins() {
|
||||
assertValid("http://test");
|
||||
assertValid("http://test:8080");
|
||||
assertValid("https://test");
|
||||
assertValid("http://test.com");
|
||||
assertValid("https://test.com");
|
||||
assertValid("https://test.com:8080");
|
||||
assertValid("http://sub.test.com");
|
||||
assertValid("https://sub.test.com");
|
||||
assertValid("https://sub.test.com:8080");
|
||||
assertValid("http://192.168.123.123");
|
||||
assertValid("https://192.168.123.123");
|
||||
assertValid("https://192.168.123.123:8080");
|
||||
assertValid("https://sub-sub.test.com");
|
||||
assertValid("https://sub.test-test.com");
|
||||
|
||||
assertInvalid("https://test/");
|
||||
assertInvalid("{");
|
||||
assertInvalid("https://{}");
|
||||
assertInvalid("https://)");
|
||||
assertInvalid("http://test:test");
|
||||
assertInvalid("http://test:8080:8080");
|
||||
}
|
||||
|
||||
public void assertValid(String origin) {
|
||||
assertTrue(UriUtils.isOrigin(origin));
|
||||
}
|
||||
|
||||
public void assertInvalid(String origin) {
|
||||
assertFalse(UriUtils.isOrigin(origin));
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Vendored
+5
-5
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -48,17 +48,17 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jpa</artifactId>
|
||||
<artifactId>keycloak-events-jpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||
<artifactId>keycloak-events-jboss-logging</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-email</artifactId>
|
||||
<artifactId>keycloak-events-email</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-mongo</artifactId>
|
||||
<artifactId>keycloak-events-mongo</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
Vendored
+4
-4
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -50,17 +50,17 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jpa</artifactId>
|
||||
<artifactId>keycloak-events-jpa</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||
<artifactId>keycloak-events-jboss-logging</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -53,6 +53,14 @@
|
||||
<directory>${project.build.directory}/unpacked/adapter</directory>
|
||||
<outputDirectory>keycloak</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/unpacked/js-adapter</directory>
|
||||
<outputDirectory>adapters/js-adapter</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.js</include>
|
||||
<include>**/*.html</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/welcome-content</directory>
|
||||
<outputDirectory>keycloak/welcome-content</outputDirectory>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -83,6 +83,13 @@
|
||||
<type>zip</type>
|
||||
<outputDirectory>${project.build.directory}/unpacked/adapter</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-js-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<outputDirectory>${project.build.directory}/unpacked/js-adapter</outputDirectory>
|
||||
<includes>*.js</includes>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
<excludes>**/welcome-content/*</excludes>
|
||||
</configuration>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/cordova" overwrite="true">
|
||||
@@ -17,7 +16,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/providers" overwrite="true">
|
||||
@@ -26,7 +24,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/js-console" overwrite="true">
|
||||
@@ -35,7 +32,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/themes" overwrite="true">
|
||||
@@ -44,7 +40,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/preconfigured-demo" overwrite="true">
|
||||
@@ -53,7 +48,6 @@
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/*.unconfigured"/>
|
||||
<exclude name="**/subsystem-config.xml"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy todir="target/examples/unconfigured-demo" overwrite="true">
|
||||
@@ -65,10 +59,9 @@
|
||||
<exclude name="**/target/**"/>
|
||||
<exclude name="**/*.iml"/>
|
||||
<exclude name="**/README.md"/>
|
||||
<exclude name="**/README.md.overview"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<copy file="../../examples/demo-template/README.md.overview" tofile="target/examples/README.md"/>
|
||||
<copy file="../../examples/README.md" tofile="target/examples/README.md"/>
|
||||
<move file="target/examples/unconfigured-demo/README.md.unconfigured" tofile="target/examples/unconfigured-demo/README.md"/>
|
||||
<move file="target/examples/unconfigured-demo/customer-app/src/main/webapp/WEB-INF/web.xml.unconfigured" tofile="target/examples/unconfigured-demo/customer-app/src/main/webapp/WEB-INF/web.xml"/>
|
||||
<move file="target/examples/unconfigured-demo/product-app/src/main/webapp/WEB-INF/web.xml.unconfigured" tofile="target/examples/unconfigured-demo/product-app/src/main/webapp/WEB-INF/web.xml"/>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||
-->
|
||||
|
||||
<project name="module-repository-lib" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
|
||||
<project name="module-repository-lib">
|
||||
|
||||
<property name="src.dir" value="src"/>
|
||||
<property name="module.repo.src.dir" value="${src.dir}/main/resources/modules"/>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Distribution</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -10,6 +10,17 @@
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/unpacked</directory>
|
||||
<outputDirectory></outputDirectory>
|
||||
<excludes>
|
||||
<exclude>**/js-adapter/**</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/unpacked/js-adapter</directory>
|
||||
<outputDirectory>adapters/js-adapter</outputDirectory>
|
||||
<includes>
|
||||
<include>**/*.js</include>
|
||||
<include>**/*.html</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<dependencySets>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -84,6 +84,13 @@
|
||||
<type>zip</type>
|
||||
<outputDirectory>${project.build.directory}/unpacked</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-js-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<outputDirectory>${project.build.directory}/unpacked/js-adapter</outputDirectory>
|
||||
<includes>*.js</includes>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -48,29 +48,7 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>replacer</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<file>${project.build.directory}/unpacked/deployments/auth-server.war/WEB-INF/classes/META-INF/keycloak-server.json</file>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>java:jboss/datasources/ExampleDS</token>
|
||||
<value>java:jboss/datasources/KeycloakDS</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
+8
-4
@@ -1,15 +1,19 @@
|
||||
<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">
|
||||
<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>
|
||||
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-reference-guide-${translation}</artifactId>
|
||||
<version>1.0-beta-4</version>
|
||||
<packaging>jdocbook</packaging>
|
||||
<name>Keycloak Reference Guide (${translation})</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss</id>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<!ENTITY JBossAdapter SYSTEM "modules/jboss-adapter.xml">
|
||||
<!ENTITY JavascriptAdapter SYSTEM "modules/javascript-adapter.xml">
|
||||
<!ENTITY InstalledApplications SYSTEM "modules/installed-applications.xml">
|
||||
<!ENTITY Logout SYSTEM "modules/logout.xml">
|
||||
<!ENTITY SocialConfig SYSTEM "modules/social-config.xml">
|
||||
<!ENTITY SocialFacebook SYSTEM "modules/social-facebook.xml">
|
||||
<!ENTITY SocialGitHub SYSTEM "modules/social-github.xml">
|
||||
@@ -25,11 +26,12 @@
|
||||
<!ENTITY DirectAccess SYSTEM "modules/direct-access.xml">
|
||||
<!ENTITY CORS SYSTEM "modules/cors.xml">
|
||||
<!ENTITY Timeouts SYSTEM "modules/timeouts.xml">
|
||||
<!ENTITY Audit SYSTEM "modules/audit.xml">
|
||||
<!ENTITY Events SYSTEM "modules/events.xml">
|
||||
<!ENTITY AdminApi SYSTEM "modules/admin-rest-api.xml">
|
||||
<!ENTITY UserFederation SYSTEM "modules/user-federation.xml">
|
||||
<!ENTITY ExportImport SYSTEM "modules/export-import.xml">
|
||||
<!ENTITY ServerCache SYSTEM "modules/cache.xml">
|
||||
<!ENTITY SecurityVulnerabilities SYSTEM "modules/security-vulnerabilities.xml">
|
||||
]>
|
||||
|
||||
<book>
|
||||
@@ -37,7 +39,7 @@
|
||||
<bookinfo>
|
||||
<title>Keycloak Reference Guide</title>
|
||||
<subtitle>SSO for Web Apps and REST Services</subtitle>
|
||||
<releaseinfo>1.0-beta-4</releaseinfo>
|
||||
<releaseinfo>&project.version;</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<toc/>
|
||||
@@ -80,6 +82,7 @@ This one is short
|
||||
&JBossAdapter;
|
||||
&JavascriptAdapter;
|
||||
&InstalledApplications;
|
||||
&Logout;
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
@@ -113,10 +116,11 @@ This one is short
|
||||
&CORS;
|
||||
&Timeouts;
|
||||
&AdminApi;
|
||||
&Audit;
|
||||
&Events;
|
||||
&UserFederation;
|
||||
&ExportImport;
|
||||
&ServerCache;
|
||||
&SecurityVulnerabilities;
|
||||
&Migration;
|
||||
|
||||
</book>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<chapter id="license">
|
||||
<title>License</title>
|
||||
<para>Keycloak is distributed under the ASL 2.0 license. It does not distribute any thirdparty libraries that are
|
||||
<para>Keycloak codebase is distributed under the ASL 2.0 license. It does not distribute any thirdparty libraries that are
|
||||
GPL. It does ship thirdparty libraries licensed under
|
||||
Apache ASL 2.0 and LGPL.
|
||||
</para>
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
<chapter id="Migration_from_older_versions">
|
||||
<title>Migration from older versions</title>
|
||||
<sect1>
|
||||
<title>Migrating from 1.0 RC-1 to RC-2</title>
|
||||
<itemizedlist>
|
||||
<listitem>A lot of info level logging has been changed to debug. Also, a realm no longer has the jboss-logging audit listener by default.
|
||||
If you want log output when users login, logout, change passwords, etc. enable the jboss-logging audit listener through the admin console.</listitem>
|
||||
</itemizedlist>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Migrating from 1.0 Beta 4 to RC-1</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
logout REST API has been refactored. The GET request on the logout URI does not take a session_state
|
||||
parameter anymore. You must be logged in in order to log out the session.
|
||||
You can also POST to the logout REST URI. This action requires a valid refresh token to perform the logout.
|
||||
The signature is the same as refresh token minus the grant type form parameter. See documentation for details.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Migrating from 1.0 Beta 1 to Beta 4</title>
|
||||
<itemizedlist>
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
of roles that an application or oauth client is allowed to ask permission for. Access tokens are always
|
||||
granted at the request of a specific application or oauth client. This also holds true for SSO. As you visit
|
||||
different sites, the application will redirect back to the Keycloak Server via the OAuth 2.0 protocol to obtain an access
|
||||
token specific to that application. The role mappings contained within the token are the union
|
||||
token specific to that application. The role mappings contained within the token are the intersection
|
||||
between the set of user role mappings and the permission scope of the application/oauth client. So,
|
||||
access tokens are tailor made for each application/oauth client and contain only the information required
|
||||
for by them.
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<listitem>
|
||||
<para>
|
||||
For OAuth clients, you would also see a "Direct Access Only" switch when creating the OAuth Client.
|
||||
This switch is for oauth clients that only use the <link linkend='direct-access-grant'>Direct Access Grant</link>
|
||||
This switch is for oauth clients that only use the <link linkend='direct-access-grants'>Direct Access Grant</link>
|
||||
protocol to obtain access tokens.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"realm-public-key" : "MIGfMA0GCSqGSIb3D...31LwIDAQAB",
|
||||
"auth-server-url" : "https://localhost:8443/auth",
|
||||
"ssl-required" : "external",
|
||||
"user-resource-role-mappings" : false,
|
||||
"use-resource-role-mappings" : false,
|
||||
"enable-cors" : true,
|
||||
"cors-max-age" : 1000,
|
||||
"cors-allowed-methods" : [ "POST", "PUT", "DELETE", "GET" ],
|
||||
@@ -101,7 +101,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>user-resource-role-mappings</term>
|
||||
<term>use-resource-role-mappings</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If set to true, the adapter will look inside the token for application level role mappings for
|
||||
|
||||
@@ -88,7 +88,7 @@ try {
|
||||
if (isPublic()) { // if client is public access type
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "customer-portal"));
|
||||
} else {
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret);
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret");
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
@@ -125,4 +125,36 @@ GET /my/rest/api
|
||||
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
To logout you must use the refresh token contained in the AccessTokenResponse object.
|
||||
</para>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||
if (isPublic()) { // if client is public access type
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "customer-portal"));
|
||||
} else {
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret");
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, tokenResponse.getRefreshToken()));
|
||||
HttpResponse response = null;
|
||||
URI logoutUri = KeycloakUriBuilder.fromUri(getBaseUrl(request) + "/auth")
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
|
||||
.build("demo");
|
||||
HttpPost post = new HttpPost(logoutUri);
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
post.setEntity(form);
|
||||
response = client.execute(post);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (status != 204) {
|
||||
error(status, entity);
|
||||
}
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
]]></programlisting>
|
||||
</chapter>
|
||||
+25
-26
@@ -1,13 +1,13 @@
|
||||
<chapter id="audit">
|
||||
<title>Audit</title>
|
||||
<chapter id="events">
|
||||
<title>Events</title>
|
||||
<para>
|
||||
Keycloak provides an Audit SPI that makes it possible to register listeners for events in the system. There are two
|
||||
interfaces that can be implemented, the first is a pure listener, the second is a provider which listens for events
|
||||
as well as providing a query over persisted events. If a realm has a audit provider registered it's possible to
|
||||
view events for the realm through the admin console and account management.
|
||||
Keycloak provides an Events SPI that makes it possible to register listeners for user related events, for example
|
||||
user logins. There are two interfaces that can be implemented, the first is a pure listener, the second is a events
|
||||
store which listens for events, but is also required to store events. An events store provides a way for the admin
|
||||
and account management consoles to view events.
|
||||
</para>
|
||||
<section>
|
||||
<title>Events</title>
|
||||
<title>Event types</title>
|
||||
<para>
|
||||
Login events:
|
||||
<itemizedlist>
|
||||
@@ -19,7 +19,7 @@
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Account events
|
||||
Account events:
|
||||
<itemizedlist>
|
||||
<listitem>Social Link - An account has been linked to a social provider</listitem>
|
||||
<listitem>Remove Social Link - A social provider has been removed from an account</listitem>
|
||||
@@ -38,14 +38,14 @@
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Audit Listener</title>
|
||||
<title>Event Listener</title>
|
||||
<para>
|
||||
Keycloak comes with an Email Audit Listener and a JBogg Logging Audit Listener. The Email Audit Listener
|
||||
sends an email to the users account when an event occurs. The JBoss Logging Audit Listener writes to a log
|
||||
Keycloak comes with an Email Event Listener and a JBogg Logging Event Listener. The Email Event Listener
|
||||
sends an email to the users account when an event occurs. The JBoss Logging Event Listener writes to a log
|
||||
file when an events occurs.
|
||||
</para>
|
||||
<para>
|
||||
The Email Audit Listener only supports the following events at the moment:
|
||||
The Email Event Listener only supports the following events at the moment:
|
||||
<itemizedlist>
|
||||
<listitem>Login Error</listitem>
|
||||
<listitem>Update Password</listitem>
|
||||
@@ -55,7 +55,7 @@
|
||||
You can exclude one or more events by editing <literal>standalone/configuration/keycloak-server.json</literal>
|
||||
and adding for example:
|
||||
<programlisting><![CDATA[
|
||||
"audit-listener": {
|
||||
"eventListener": {
|
||||
"email": {
|
||||
"exclude-events": [ "UPDATE_TOTP", "REMOVE_TOTP" ]
|
||||
}
|
||||
@@ -65,18 +65,17 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Audit Provider</title>
|
||||
<title>Event Store</title>
|
||||
<para>
|
||||
Audit Providers listen for events and is expected to persist the events to make it possible to query for them
|
||||
Event Store listen for events and is expected to persist the events to make it possible to query for them
|
||||
later. This is used by the admin console and account management to view events. Keycloak includes providers
|
||||
to persist audit events to JPA and Mongo. For production you will most likely want to use a separate database
|
||||
for audit events. You may even want to use a RDBMS for your model, and Mongo for your audit.
|
||||
to persist events to JPA and Mongo.
|
||||
</para>
|
||||
<para>
|
||||
You can specify events to include or exclude by editing <literal>standalone/configuration/keycloak-server.json</literal>,
|
||||
and adding for example:
|
||||
<programlisting><![CDATA[
|
||||
"audit": {
|
||||
"eventsStore": {
|
||||
"jpa": {
|
||||
"exclude-events": [ "LOGIN", "REFRESH_TOKEN", "CODE_TO_TOKEN" ]
|
||||
}
|
||||
@@ -86,18 +85,18 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Configure Audit Settings for Realm</title>
|
||||
<title>Configure Events Settings for Realm</title>
|
||||
<para>
|
||||
To enable audit for a realm you firstly need to make sure you have a audit provider registered for Keycloak.
|
||||
By default the JPA audit provider is registered. Once you've done that open the admin console, select the
|
||||
realm you're configuring, select <literal>Audit</literal>. Then click on <literal>Config</literal>.
|
||||
You can enable audit for your realm by toggling <literal>Enabled</literal> to ON. You can also set
|
||||
an expiration on audit events. This will deleted events from the database that are older than the specified
|
||||
To enable persisting of events for a realm you first need to make sure you have a event store provider registered for Keycloak.
|
||||
By default the JPA event store provider is registered. Once you've done that open the admin console, select the
|
||||
realm you're configuring, select <literal>Events</literal>. Then click on <literal>Config</literal>.
|
||||
You can enable storing events for your realm by toggling <literal>Save Events</literal> to ON. You can also set
|
||||
an expiration on events. This will periodically delete events from the database that are older than the specified
|
||||
time.
|
||||
</para>
|
||||
<para>
|
||||
To configure listeners for a realm on the same page as above add one or more audit listeners to the <literal>
|
||||
Audit Listeners</literal> select box. This will allow you to enable any registered Audit Listeners with the
|
||||
To configure listeners for a realm on the same page as above add one or more event listeners to the
|
||||
<literal>Listeners</literal> select box. This will allow you to enable any registered event listeners with the
|
||||
realm.
|
||||
</para>
|
||||
</section>
|
||||
Regular → Executable
+9
-1
@@ -47,6 +47,14 @@ bin/standalone.sh -Dkeycloak.migration.action=export
|
||||
<programlisting><![CDATA[
|
||||
bin/standalone.sh -Dkeycloak.migration.action=export
|
||||
-Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=<FILE TO EXPORT TO>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Here's an example of importing:
|
||||
<programlisting><![CDATA[
|
||||
bin/standalone.sh -Dkeycloak.migration.action=import
|
||||
-Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=<FILE TO IMPORT>
|
||||
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING
|
||||
]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
@@ -92,7 +100,7 @@ bin/standalone.sh -Dkeycloak.migration.action=export
|
||||
is used during import. It can be used to specify how to proceed if realm with same name
|
||||
already exists in the database where you are going to import data. Possible values are:
|
||||
<itemizedlist>
|
||||
<listitem>IGNORE_EXISTING - Ignore exporting if realm of this name already exists</listitem>
|
||||
<listitem>IGNORE_EXISTING - Ignore importing if realm of this name already exists</listitem>
|
||||
<listitem>OVERWRITE_EXISTING - Remove existing realm and import it again with new data from JSON file.
|
||||
If you want to fully migrate one environment to another and ensure that the new environment will contain same data
|
||||
like the old one, you can specify this.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<section>
|
||||
<section id="jboss-adapter">
|
||||
<title>JBoss/Wildfly Adapter</title>
|
||||
<para>
|
||||
To be able to secure WAR apps deployed on JBoss AS 7.1.1, JBoss EAP 6.x, or Wildfly, you must install and
|
||||
@@ -7,7 +7,7 @@
|
||||
to crack open your WARs at all and can apply Keycloak via the Keycloak Subsystem configuration in standalone.xml.
|
||||
Both methods are described in this section.
|
||||
</para>
|
||||
<section>
|
||||
<section id="jboss-adapter-installation">
|
||||
<title>Adapter Installation</title>
|
||||
<para>
|
||||
This is a adapter zip file for AS7, EAP, and Wildfly in the <literal>adapters/</literal> directory in the Keycloak
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<section>
|
||||
<title>Logout</title>
|
||||
<para>
|
||||
There are multiple ways you can logout from a web application. For Java EE servlet containers, you can call
|
||||
HttpServletRequest.logout().
|
||||
For any other browser application, you can point the browser at the url <literal>http://auth-server/auth/realms/{realm-name}/tokens/logout?redirect_uri=encodedRedirectUri</literal>.
|
||||
This will log you out if you have an SSO session with your browser.
|
||||
</para>
|
||||
</section>
|
||||
@@ -0,0 +1,155 @@
|
||||
<chapter id="security_vulnerabilities">
|
||||
<title>Security Vulnerabilities</title>
|
||||
<para>
|
||||
This chapter discusses possible security vulnerabilities Keycloak could have, how Keycloak mitigates those
|
||||
vulnerabilities, and what steps you need to do to configure Keycloak to mitigate some vulnerabilities. A good list
|
||||
of potential vulnerabilities and what security implementations should do to mitigate them can be found in the
|
||||
<ulink url="http://tools.ietf.org/html/rfc6819">OAuth 2.0 Thread Model</ulink> document put out by the IETF. Many of those vulnerabilities are discussed here.
|
||||
</para>
|
||||
<section>
|
||||
<title>SSL/HTTPS Requirement</title>
|
||||
<para>
|
||||
If you do not use SSL/HTTPS for all communication between the Keycloak auth server and the clients it secures
|
||||
you will be very vulnerable to man in the middle attacks. OAuth 2.0/OpenID Connect uses access tokens for
|
||||
security. Without SSL/HTTPS, attackers can sniff your network and obtain an access token. Once they have an
|
||||
access token they can do any operation that the token has been given permission for.
|
||||
</para>
|
||||
<para>
|
||||
Keycloak has <link linkend="ssl_modes">three modes for SSL/HTTPS</link>. SSL can be hard to set up, so out of the box, Keycloak allows
|
||||
non-HTTPS communication over private IP addresses like localhost, 192.168.x.x, and other private IP addresses.
|
||||
In production, you should make sure SSL is enabled and required across the board.
|
||||
</para>
|
||||
<para>
|
||||
On the adapter/client side, Keycloak allows you to turn off the SSL trust manager. The trust manager ensures
|
||||
identity the client is talking to. It checks the DNS domain name against the server's certificate. In production
|
||||
you should make sure that each of your client adapters is configured to use a truststore. Otherwise you are vulnerable
|
||||
to DNS man in the middle attacks.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>CSRF Attacks</title>
|
||||
<para>
|
||||
Cross-site request forgery (CSRF) is a web-based attack whereby HTTP
|
||||
requests are transmitted from a user that the web site trusts or has
|
||||
authenticated (e.g., via HTTP redirects or HTML forms). Any site that uses
|
||||
cookie based authentication is vulnerable for these types of attacks. These attacks are mitigated
|
||||
by matching a state cookie against a posted form or query parameter.
|
||||
</para>
|
||||
<para>
|
||||
OAuth 2.0 login specification requires that a state cookie be used and matched against a transmitted state
|
||||
parameter. Keycloak fully implements this part of the specification so all logins are protected.
|
||||
</para>
|
||||
<para>
|
||||
The Keycloak adminstration console is a pure Javascript/HTML5 application that makes REST calls to the
|
||||
backend Keycloak admin API. These calls all require bearer token authentication and are made via Javascript
|
||||
Ajax calls. CSRF does not apply here. The admin REST API can also be configured to validate CORS origins
|
||||
as well.
|
||||
</para>
|
||||
<para>
|
||||
The only part of Keycloak that really falls into CSRF is the user account management pages. To mitigate this
|
||||
Keycloak sets a state cookie and also embeds the value of this state cookie within hidden form fields or
|
||||
query parameters in action links. This query or form parameter is checked against the state cookie to verify
|
||||
that the call was made by the user.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Clickjacking</title>
|
||||
<para>
|
||||
With clickjacking, a malicious site loads the target site in a
|
||||
transparent iFrame overlaid on top of a set of dummy
|
||||
buttons that are carefully constructed to be placed directly under
|
||||
important buttons on the target site. When a user clicks a visible
|
||||
button, they are actually clicking a button (such as an "Authorize"
|
||||
button) on the hidden page. An attacker can steal a user's authentication credentials and
|
||||
access their resources.
|
||||
</para>
|
||||
<para>
|
||||
By default, every response by Keycloak sets some specific browser headers that can prevent this from happening
|
||||
specifically <ulink url="http://tools.ietf.org/html/rfc7034">X-FRAME_OPTIONS</ulink> and <ulink url="http://www.w3.org/TR/CSP/">Content-Security-Policy</ulink>. You
|
||||
should take a look at both of these headers. In the admin console you can specify the values these headers will
|
||||
have. By default, Keycloak only sets up a same-origin policy for iframes.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Compromised Access Codes</title>
|
||||
<para>
|
||||
It would be very hard for an attacker to compromise Keycloak access codes. Keycloak generates a cryptographically
|
||||
strong random value for its access codes so it would be very hard to guess an access token.
|
||||
An access code can only be turned into an access token once so it can't be replayed. In the admin console
|
||||
you can specify how long an access token is valid for. This value should be really short. Like a seconds.
|
||||
Just long enough for the client to make the request to turn the code into an token.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Compromised access and refresh tokens</title>
|
||||
<para>
|
||||
There's a few things you can do to mitigate access tokens and refresh tokens from being stolen.
|
||||
Most importantly is to enforce SSL/HTTPS communication between Keycloak and its clients and applications.
|
||||
Short lifespans (minutes) for access tokens allows Keycloak to check the validity of a refresh token. Making
|
||||
sure refresh tokens always stay private to the client and are never transmitted ever is very important as well.
|
||||
</para>
|
||||
<para>
|
||||
If an access token or refresh token is compromised, the first thing you should do is go to the admin console
|
||||
and push a not-before revocation policy to all applications. This will enforce that any tokens issued
|
||||
prior to that date are now invalid. You can also disable specific applications, clients, and users if you
|
||||
feel that any one of those entities is completely compromised.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Open redirectors</title>
|
||||
<para>
|
||||
An attacker could use the end-user authorization endpoint and the
|
||||
redirect URI parameter to abuse the authorization server as an open
|
||||
redirector. An open redirector is an endpoint using a parameter to
|
||||
automatically redirect a user agent to the location specified by the
|
||||
parameter value without any validation. An attacker could utilize a user's trust in an authorization
|
||||
server to launch a phishing attack.
|
||||
</para>
|
||||
<para>
|
||||
Keycloak requires that all registered applications and clients register at least one redirection uri pattern.
|
||||
Any time a client asks Keycloak to perform a redirect (on login or logout for example), Keycloak will
|
||||
check the redirect uri vs. the list of valid registered uri patterns. It is important that clients and
|
||||
applications register as specific a URI pattern as possible to mitigate open redirector attacks.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Password guess: brute force attacks</title>
|
||||
<para>
|
||||
A brute force attack happens when an attacker is trying to guess a user's password. Keycloak has some
|
||||
limited brute force detection capabilities. If turned on, a user account will be temporarily disabled
|
||||
if a threshold of login failures is reached. The downside of this is that this makes Keycloak vulnerable
|
||||
to denial of service attacks. Eventually we will expand this functionality to take client IP address into
|
||||
account when deciding whether to block a user.
|
||||
</para>
|
||||
<para>
|
||||
Another thing you can do to prevent password guessing is to point a tool like <ulink url="http://fail2ban.org">Fail2Ban</ulink> to the Keycloak
|
||||
server's log file. Keycloak logs every login failure and client IP address that had the failure.
|
||||
</para>
|
||||
<para>
|
||||
In the admin console, per realm, you can set up a password policy to enforce that users pick hard to guess passwords.
|
||||
</para>
|
||||
<para>
|
||||
Finally, the best way to mitigate against brute force attacks is to require user to set up a one-time-password (OTP).
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Password database compromised</title>
|
||||
<para>
|
||||
Keycloak does not store passwords in raw text. It stores a hash of them. Because of performance reasons,
|
||||
Keycloak only hashes passwords once. While a human could probably never crack a hashed password, it is very
|
||||
possible that a computer could. The security community suggests around 20,000 (yes thousand!) hashing iterations
|
||||
to be done to each password. This number grows every year due to increasing computing power (It was 1000 12 years ago).
|
||||
The problem with this is that password hashing is a huge performance hit as each login would require the entered
|
||||
password to be hashed that many times and compared to the stored hash. So, its up to the admin to configure the
|
||||
password hash iterations. This can be done in the admin console password policy configuration. Again, the default
|
||||
value is 1 as we thought it might be more important for Keycloak to scale out of the box. There's a lot of
|
||||
other measures admins can do to protect their password databases.
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>SQL Injection attacks</title>
|
||||
<para>
|
||||
At this point in time, there is no knowledge of any SQL injection vulnerabilities in Keycloak
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -8,11 +8,11 @@
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
keycloak-appliance-dist-all-1.0-beta-4.zip
|
||||
keycloak-appliance-dist-all-&project.version;.zip
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
keycloak-war-dist-all-1.0-beta-4.zip
|
||||
keycloak-war-dist-all-&project.version;.zip
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
@@ -22,7 +22,7 @@
|
||||
<title>Appliance Install</title>
|
||||
<para>
|
||||
The
|
||||
<literal>keycloak-appliance-dist-all.zip</literal>
|
||||
<literal>keycloak-appliance-dist-all-&project.version;.zip</literal>
|
||||
is quite large, but contains a complete server (backed by Wildfly)
|
||||
that runs out of the box. The only thing you'll have to enable and configure is SSL. Unzipping it, the
|
||||
directory layout looks
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
<para>
|
||||
<programlisting>
|
||||
keycloak-appliance-dist-all-1.0-beta-4/
|
||||
keycloak-appliance-dist-all-&project.version;/
|
||||
keycloak/
|
||||
bin/
|
||||
standalone.sh
|
||||
@@ -42,9 +42,9 @@ keycloak-appliance-dist-all-1.0-beta-4/
|
||||
keycloak-server.json
|
||||
themes/
|
||||
adapters/
|
||||
keycloak-as7-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-eap6-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-wildfly-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-as7-adapter-dist-&project.version;.zip
|
||||
keycloak-eap6-adapter-dist-&project.version;.zip
|
||||
keycloak-wildfly-adapter-dist-&project.version;.zip
|
||||
examples/
|
||||
docs/
|
||||
</programlisting>
|
||||
@@ -67,7 +67,7 @@ keycloak-appliance-dist-all-1.0-beta-4/
|
||||
<title>WAR Distribution Installation</title>
|
||||
<para>
|
||||
The
|
||||
<literal>keycloak-war-dist-all.zip</literal>
|
||||
<literal>keycloak-war-dist-all-&project.version;.zip</literal>
|
||||
contains
|
||||
just the bits you need to install keycloak on your favorite web container. We currently only support
|
||||
installing it on top of an existing JBoss AS 7.1.1, JBoss EAP 6.x, or Wildfly 8 distribution. We may in the
|
||||
@@ -79,7 +79,7 @@ keycloak-appliance-dist-all-1.0-beta-4/
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
keycloak-war-dist-all-1.0-beta-4/
|
||||
keycloak-war-dist-all-&project.version;/
|
||||
deployments/
|
||||
auth-server.war/
|
||||
keycloak-ds.xml
|
||||
@@ -87,9 +87,9 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
keycloak-server.json
|
||||
themes/
|
||||
adapters/
|
||||
keycloak-as7-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-eap6-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-wildfly-adapter-dist-1.0-beta-4.zip
|
||||
keycloak-as7-adapter-dist-&project.version;.zip
|
||||
keycloak-eap6-adapter-dist-&project.version;.zip
|
||||
keycloak-wildfly-adapter-dist-&project.version;.zip
|
||||
examples/
|
||||
docs/
|
||||
</programlisting>
|
||||
@@ -101,10 +101,16 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
$ cd keycloak-war-dist-all-1.0-beta-4
|
||||
$ cd keycloak-war-dist-all-&project.version;
|
||||
$ cp -r deployments $JBOSS_HOME/standalone
|
||||
$ cp -r configuration $JBOSS_HOME/standalone
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
After these steps you should also <link linkend='jboss-adapter-installation'>install the client adapter</link>
|
||||
as this may contain modules the server needs (like Bouncycastle). You will also need to install the adapter
|
||||
to run the examples on the same server.
|
||||
</para>
|
||||
<para>
|
||||
After booting up the JBoss or Wildfly distro, you can then make sure it is installed properly
|
||||
by logging into the admin console at<ulink
|
||||
@@ -123,7 +129,7 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
Configuring keycloak to use a production database.
|
||||
Configuring Keycloak to use a production database.
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@@ -136,16 +142,16 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<section>
|
||||
<title>Database Configuration</title>
|
||||
<title>Relational Database Configuration</title>
|
||||
<para>
|
||||
The datasource used to store Keycloak data is configured in the <literal>.../standalone/deployments/keycloak-ds.xml</literal>
|
||||
file of your Keycloak Server installation if you used <xref linkend="WAR_distribution_installation" /> or in <literal>.../standalone/configuration/standalone.xml</literal>
|
||||
By default, Keycloak uses a relational database to store Keycloak data. This datasource is the <literal>standalone/deployments/keycloak-ds.xml</literal>
|
||||
file of your Keycloak Server installation if you used <xref linkend="WAR_distribution_installation" /> or in <literal>standalone/configuration/standalone.xml</literal>
|
||||
if you used <xref linkend="Appliance_install" />. File <literal>keycloak-ds.xml</literal> is used in WAR
|
||||
distribution, so that you have datasource available out of the box and you don't need to edit <literal>standalone.xml</literal> file.
|
||||
However a good thing is to always delete the file <literal>keycloak-ds.xml</literal> and move its configuration text
|
||||
into the centrally managed <literal>standalone.xml</literal> file.
|
||||
This will allow you to manage the database connection pool from the Wildfly/JBoss administration console. Here's what
|
||||
<literal>.../standalone/configuration/standalone.xml</literal> should look like after you've done this:
|
||||
<literal>standalone/configuration/standalone.xml</literal> should look like after you've done this:
|
||||
</para>
|
||||
<para>
|
||||
<programlisting><![CDATA[
|
||||
@@ -174,8 +180,8 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
|
||||
</driver>
|
||||
</drivers>
|
||||
</datasources>
|
||||
</subsystem>
|
||||
</datasources>
|
||||
</subsystem>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -188,22 +194,87 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
</para>
|
||||
<para>
|
||||
Keycloak also runs on a Hibernate/JPA backend which is configured in the
|
||||
<literal>.../standalone/deployments/auth-server.war/WEB-INF/classes/META-INF/persistence.xml</literal>.
|
||||
Please see the <ulink url="http://hibernate.org/orm/documentation/">Hibernate and JPA documentation</ulink> for more information on tweaking the backend datamodel.
|
||||
<literal>standalone/configuration/keycloak-server.json</literal>.
|
||||
By default the setting is like this:
|
||||
<programlisting><![CDATA[
|
||||
"connectionsJpa": {
|
||||
"default": {
|
||||
"dataSource": "java:jboss/datasources/KeycloakDS",
|
||||
"databaseSchema": "update"
|
||||
}
|
||||
},
|
||||
]]></programlisting>
|
||||
Possible configuration options are:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>dataSource</term>
|
||||
<listitem>
|
||||
<para>
|
||||
JNDI name of the dataSource
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>jta</term>
|
||||
<listitem>
|
||||
<para>
|
||||
boolean property to specify if datasource is JTA capable
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>driverDialect</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Value of Hibernate dialect. In most cases you don't need to specify this property as dialect will be
|
||||
autodetected by Hibernate.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>databaseSchema</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Value of database schema (Hibernate property "hibernate.hbm2ddl.auto" ).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>showSql</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify whether Hibernate should show all SQL commands in the console (false by default)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>formatSql</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify whether Hibernate should format SQL commands (true by default)
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>unitName</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allow you to specify name of persistence unit if you want to provide your own persistence.xml file for JPA configuration.
|
||||
If this option is used, then all other configuration options are ignored as you are expected to configure
|
||||
all JPA/DB properties in your own persistence.xml file. Hence you can remove properties "dataSource" and "databaseSchema" in this case.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
For more info about Hibernate properties, see <ulink url="http://hibernate.org/orm/documentation/">Hibernate and JPA documentation</ulink> .
|
||||
</para>
|
||||
<section>
|
||||
<title>Tested databases</title>
|
||||
<para>
|
||||
Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. Note that Hibernate dialect
|
||||
is usually set automatically according to your database, but in some cases, you must manually set the proper dialect,
|
||||
as the default dialect may not work correctly. You can setup dialect either by adding property <literal>hibernate.dialect</literal>
|
||||
to the <literal>persistence.xml</literal> file mentioned above or simply by adding system property <literal>hibernate.dialect</literal>
|
||||
with corresponding value. For example, if you are using MS-SQL you can start keycloak with command:
|
||||
<programlisting><![CDATA[
|
||||
./standalone.sh -Dhibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
|
||||
]]></programlisting>
|
||||
This command will set system property <literal>hibernate.dialect</literal> to value <literal>org.hibernate.dialect.SQLServer2008Dialect</literal>
|
||||
and this one will take precedence over the value from <literal>persistence.xml</literal> file.
|
||||
as the default dialect may not work correctly. You can setup dialect by adding property <literal>driverDialect</literal>
|
||||
to the <literal>keycloak-server.json</literal> into <literal>connectionsJpa</literal> section (see above).
|
||||
<table frame='all'><title>Tested databases</title>
|
||||
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
|
||||
<thead>
|
||||
@@ -258,55 +329,56 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
in your favourite editor, then change:
|
||||
|
||||
<programlisting><![CDATA[
|
||||
"audit": {
|
||||
"provider": "jpa",
|
||||
"jpa": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ]
|
||||
}
|
||||
"eventsStore": {
|
||||
"provider": "jpa",
|
||||
"jpa": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ]
|
||||
}
|
||||
},
|
||||
|
||||
"model": {
|
||||
"provider": "jpa"
|
||||
"realm": {
|
||||
"provider": "jpa"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"provider": "${keycloak.user.provider:jpa}"
|
||||
},
|
||||
]]></programlisting>
|
||||
|
||||
to:
|
||||
|
||||
<programlisting><![CDATA[
|
||||
"audit": {
|
||||
"provider": "mongo",
|
||||
"mongo": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ],
|
||||
"host": "<hostname>",
|
||||
"port": <port>,
|
||||
"user": "<user>",
|
||||
"password": "<password>",
|
||||
"db": "<db name>"
|
||||
}
|
||||
"eventsStore": {
|
||||
"provider": "mongo",
|
||||
"mongo": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ]
|
||||
}
|
||||
},
|
||||
|
||||
"model": {
|
||||
"provider": "mongo",
|
||||
"mongo": {
|
||||
"host": "<hostname>",
|
||||
"port": <port>,
|
||||
"user": "<user>",
|
||||
"password": "<password>",
|
||||
"db": "<db name>"
|
||||
}
|
||||
"realm": {
|
||||
"provider": "mongo"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"provider": "mongo"
|
||||
},
|
||||
]]></programlisting>
|
||||
|
||||
All configuration options are optional. Default values for host and port are localhost and 27017. If
|
||||
user and password are not specified Keycloak will connect unauthenticated to your MongoDB. Finally, default
|
||||
values for db are keycloak for the model, and keycloak-audit for audit.
|
||||
And at the end of the file add the snippet like this where you can configure details about your Mongo database:
|
||||
<programlisting><![CDATA[
|
||||
"connectionsMongo": {
|
||||
"default": {
|
||||
"host": "127.0.0.1",
|
||||
"port": "27017",
|
||||
"db": "keycloak"
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
|
||||
If you switch to Mongo model, it could be a good idea to remove RDBMS related stuff from your distribution to reduce startup time and memory footprint.
|
||||
To do it, you need to:
|
||||
<itemizedlist>
|
||||
<listitem>Comment/remove datasource <literal>KeycloakDS</literal> from <literal>standalone/configuration/standalone.xml</literal> or <literal>standalone/deployments/keycloak-ds.xml</literal></listitem>
|
||||
<listitem>Remove file <literal>standalone/deployments/auth-server.war/WEB-INF/classes/META-INF/persistence.xml</literal></listitem>
|
||||
</itemizedlist>
|
||||
All configuration options are optional. Default values for host and port are localhost and 27017. Default name of database
|
||||
is <literal>keycloak</literal> . You can also specify properties <literal>user</literal> and <literal>password</literal>
|
||||
if you want authenticate against your MongoDB. If user and password are not specified, Keycloak will connect
|
||||
unauthenticated to your MongoDB.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -332,8 +404,8 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
]]>
|
||||
</programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>SSL/HTTPS Setup</title>
|
||||
<section id="ssl_modes">
|
||||
<title>SSL/HTTPS Requirement/Modes</title>
|
||||
<warning>
|
||||
<para>
|
||||
Keycloak is not set up by default to handle SSL/HTTPS in either the
|
||||
@@ -341,6 +413,47 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
itself or on a reverse proxy in front of the Keycloak server.
|
||||
</para>
|
||||
</warning>
|
||||
<para>
|
||||
Keycloak can run out of the box without SSL so long as you stick to private IP addresses like
|
||||
localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. If you try to access Keycloak from a
|
||||
non-IP adress you will get an error.
|
||||
</para>
|
||||
<para>
|
||||
Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page
|
||||
and the <literal>Require SSL</literal> select box. Each adapter config should mirror this server-side
|
||||
setting. See adapter config section for more details.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>external</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Keycloak can run out of the box without SSL so long as you stick to private IP addresses like
|
||||
localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. If you try to access Keycloak from a
|
||||
non-IP adress you will get an error.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>none</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Keycloak does not require SSL.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>all</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Keycloak requires SSL for all IP addresses.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>SSL/HTTPS Setup</title>
|
||||
|
||||
<para>
|
||||
First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. Then configure the Keycloak Server to enforce HTTPS connections.
|
||||
@@ -512,29 +625,74 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
<literal>X-Forwarded-Proto</literal> headers on the requests made to Keycloak. Next you need to enable
|
||||
<literal>proxy-address-forwarding</literal> on the Keycloak http connector. Assuming that your reverse
|
||||
proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to.
|
||||
This is done by editing <literal>standalone/configuration/standalone.xml</literal>.
|
||||
</para>
|
||||
First add <literal>proxy-address-forwarding</literal> and <literal>redirect-socket</literal> to the <literal>http-listener</literal>
|
||||
element:
|
||||
<para>
|
||||
|
||||
<section>
|
||||
<title>WildFly</title>
|
||||
|
||||
<para>
|
||||
Open <literal>standalone/configuration/standalone.xml</literal> in your favorite editor.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
First add <literal>proxy-address-forwarding</literal> and <literal>redirect-socket</literal> to
|
||||
the <literal>http-listener</literal> element:
|
||||
<programlisting><![CDATA[<subsystem xmlns="urn:jboss:domain:undertow:1.1">
|
||||
...
|
||||
<http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="proxy-https"/>
|
||||
<http-listener name="default" socket-binding="http"
|
||||
proxy-address-forwarding="true" redirect-socket="proxy-https"/>
|
||||
...
|
||||
</subsystem>
|
||||
]]></programlisting>
|
||||
Then add a new <literal>socket-binding</literal> element to the <literal>socket-binding-group</literal> element:
|
||||
</para>
|
||||
<para>
|
||||
Then add a new <literal>socket-binding</literal> element to the <literal>socket-binding-group</literal> element:
|
||||
<programlisting><![CDATA[
|
||||
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
|
||||
<socket-binding-group name="standard-sockets" default-interface="public"
|
||||
port-offset="${jboss.socket.binding.port-offset:0}">
|
||||
...
|
||||
<socket-binding name="proxy-https" port="443"/>
|
||||
...
|
||||
</socket-binding-group>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Check the <ulink url="https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration">WildFly</ulink> documentation for more information.
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
Check the <ulink url="https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration">WildFly</ulink> documentation for more information.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>AS7/EAP</title>
|
||||
|
||||
<para>
|
||||
Open <literal>standalone/configuration/standalone.xml</literal> in your favorite editor.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You need to add <literal>redirect-port</literal> to http <literal>connector</literal> element and
|
||||
add the <literal>RemoteIpValve</literal> valve:
|
||||
<programlisting><![CDATA[
|
||||
<subsystem xmlns="urn:jboss:domain:web:1.5"
|
||||
default-virtual-server="default-host" native="false">
|
||||
<connector name="http" protocol="HTTP/1.1" scheme="http"
|
||||
socket-binding="http"
|
||||
redirect-port="443"/>
|
||||
<virtual-server name="default-host" enable-welcome-root="true">
|
||||
<alias name="localhost"/>
|
||||
<alias name="example.com"/>
|
||||
</virtual-server>
|
||||
<valve name="remoteipvalve" module="org.jboss.as.web"
|
||||
class-name="org.apache.catalina.valves.RemoteIpValve">
|
||||
<param param-name="protocolHeader" param-value="x-forwarded-proto"/>
|
||||
</valve>
|
||||
</subsystem>
|
||||
]]></programlisting>
|
||||
</para>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -558,17 +716,6 @@ keycloak-war-dist-all-1.0-beta-4/
|
||||
</web-app>]]></programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Enforce HTTPS at Realm Level</title>
|
||||
<para>
|
||||
In Keycloak, each realm has an "Require SSL" switch that you should turn on. Log into the
|
||||
adminstration console and set this switch for each realm that Keycloak manages. This switch is on
|
||||
the <literal>Settings>>General</literal> page. While this switch does do similar checks as the security
|
||||
constraint in <literal>web.xml</literal>, it will also force applications and oauth clients to only
|
||||
register HTTPS based redirect URLs.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
Regular → Executable
+4
-2
@@ -18,7 +18,8 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Once the app has been created click on <literal>Settings</literal> in sidebar on the left. Then click
|
||||
Once the app has been created click on <literal>Settings</literal> in sidebar on the left. You must specify
|
||||
a contact email. Save your changes. Then click
|
||||
on <literal>Advanced</literal>. Under <literal>Security</literal> make sure
|
||||
<literal>Client OAuth Login</literal> is enabled. In <literal>Valid OAuth redirect URIs</literal> insert
|
||||
the <link linkend="social-callbackurl">social callback url</link>. Scroll down and click on the
|
||||
@@ -28,7 +29,8 @@
|
||||
<listitem>
|
||||
<para>
|
||||
Click <literal>Status & Review</literal> and select <literal>YES</literal> for <literal>Do you want
|
||||
to make this app and all its live features available to the general public?</literal>.
|
||||
to make this app and all its live features available to the general public?</literal>. You will
|
||||
not be able to set this until you have provided a contact email in the general settings of this application.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
||||
Regular → Executable
+1
-1
@@ -1,7 +1,7 @@
|
||||
<section id="social-github">
|
||||
<title>GitHub</title>
|
||||
<para>
|
||||
To enable login with Google you first have to create an application in
|
||||
To enable login with GitHub you first have to create an application in
|
||||
<ulink url="https://github.com/settings/applications">GitHub Settings</ulink>. Then you need to copy
|
||||
the client id and secret into the Keycloak Admin Console.
|
||||
</para>
|
||||
|
||||
Regular → Executable
+7
-5
@@ -22,6 +22,13 @@
|
||||
the list and the status should be <literal>ON</literal>).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Now click on the <literal>Consent screen</literal> link on the sidebar menu on the left. You must specify
|
||||
a project name and choose an email for the consent screen. Otherwise users will get a login error. There's
|
||||
other things you can configure here like what the consent screen looks like. Feel free to play around with this.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Now click <literal>Credentials</literal> in the sidebar on the left. Then click
|
||||
@@ -40,9 +47,4 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>
|
||||
You may also want to configure how the Google Consent Screen looks when users log in to your application via
|
||||
Google. To do this go to <ulink url="https://cloud.google.com/console/project">Google Developer Console</ulink>
|
||||
and click on <literal>Consent Screen</literal> in the sidebar to the left.
|
||||
</para>
|
||||
</section>
|
||||
Regular → Executable
+1
-1
@@ -22,7 +22,7 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Now click <literal>Details</literal>. Copy <literal>Consumer key</literal> and <literal>Consumer secret</literal> from the
|
||||
Now click <literal>API Keys</literal> tab. Copy <literal>API key</literal> and <literal>API secret</literal> from the
|
||||
<ulink url="https://dev.twitter.com/apps">Twitter Developer Console</ulink> into the settings
|
||||
page in the Keycloak Admin Console as the <literal>Key</literal> and <literal>Secret</literal>. Then click
|
||||
<literal>Save</literal> in the Keycloak Admin Console to enable login with Twitter.
|
||||
|
||||
@@ -6,13 +6,37 @@
|
||||
and feel of end-user facing pages so they can be integrated with your brand and applications.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Theme types</title>
|
||||
<para>
|
||||
There are several types of themes in Keycloak:
|
||||
<itemizedlist>
|
||||
<listitem>Account - Account management</listitem>
|
||||
<listitem>Admin - Admin console</listitem>
|
||||
<listitem>Common - Shared resources for themes</listitem>
|
||||
<listitem>Email - Emails</listitem>
|
||||
<listitem>Login - Login forms</listitem>
|
||||
<listitem>Welcome - Welcome pages</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Configure theme</title>
|
||||
<para>
|
||||
To configure the theme used by a realm open the <literal>Keycloak Admin Console</literal>, select your realm
|
||||
from the drop-down box in the top left corner. In the <literal>Optional Settings</literal> use the drop-down
|
||||
boxes for <literal>Login Theme</literal> and <literal>Account Theme</literal> to select the theme used
|
||||
by login forms and account management pages.
|
||||
All theme types, except welcome, is configured through <literal>Keycloak Admin Console</literal>. To change
|
||||
the theme used for a realm open the open the <literal>Keycloak Admin Console</literal>, select your realm
|
||||
from the drop-down box in the top left corner. Under <literal>Settings</literal> click on <literal>Theme</literal>.
|
||||
</para>
|
||||
<para>
|
||||
To change the welcome theme you need to edit <literal>standalone/configuration/keycloak-server.json</literal>
|
||||
and add <literal>welcomeTheme</literal> to the theme element, for example:
|
||||
<programlisting>
|
||||
"theme": {
|
||||
...
|
||||
"welcomeTheme": "custom-theme"
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -27,26 +51,15 @@
|
||||
|
||||
<section>
|
||||
<title>Creating a theme</title>
|
||||
<para>
|
||||
There are several types of themes in Keycloak:
|
||||
<itemizedlist>
|
||||
<listitem>Account - Account management</listitem>
|
||||
<listitem>Admin - Admin console</listitem>
|
||||
<listitem>Common - Shared resources for themes</listitem>
|
||||
<listitem>Email - Emails</listitem>
|
||||
<listitem>Login - Login forms</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A theme consists of:
|
||||
<itemizedlist>
|
||||
<listitem><para><ulink url="http://freemarker.org">FreeMarker</ulink> templates</para></listitem>
|
||||
<listitem><para>Stylesheets</para></listitem>
|
||||
<listitem><para>Scripts</para></listitem>
|
||||
<listitem><para>Images</para></listitem>
|
||||
<listitem><para>Message bundles</para></listitem>
|
||||
<listitem><para>Theme properties</para></listitem>
|
||||
<listitem><ulink url="http://freemarker.org">FreeMarker</ulink> templates</listitem>
|
||||
<listitem>Stylesheets</listitem>
|
||||
<listitem>Scripts</listitem>
|
||||
<listitem>Images</listitem>
|
||||
<listitem>Message bundles</listitem>
|
||||
<listitem>Theme properties</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
@@ -56,7 +69,7 @@
|
||||
templates.
|
||||
</para>
|
||||
<para>
|
||||
To create a new theme, create a folder in <literal>.../standalone/configuration/themes/< theme type></literal>.
|
||||
To create a new theme, create a folder in <literal>.../standalone/configuration/themes/<theme type></literal>.
|
||||
The name of the folder is the name of the theme. Then create a file <literal>theme.properties</literal> inside the theme folder.
|
||||
The contents of the file should be:
|
||||
</para>
|
||||
@@ -79,6 +92,7 @@
|
||||
<programlisting>styles=css/styles.css css/more-styles.css</programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<title>Scripts</title>
|
||||
<para>
|
||||
A theme can have one or more scripts, to add a script create a file inside <literal>resources/js</literal> (for example <literal>resources/js/script.js</literal>)
|
||||
inside your theme folder. Then registering it in <literal>theme.properties</literal> by adding:
|
||||
@@ -133,10 +147,9 @@
|
||||
<section>
|
||||
<title>Theme SPI</title>
|
||||
<para>
|
||||
The Theme SPI allows creating different mechanisms to providing themes for the default FreeMarker based
|
||||
The Theme SPI allows creating different mechanisms to load themes for the default FreeMarker based
|
||||
implementations of login forms and account management. To create a theme provider you will need to implement
|
||||
<literal>org.keycloak.freemarker.ThemeProvider</literal> and <literal>org.keycloak.freemarker.Theme</literal> in
|
||||
<literal>forms/common-freemarker</literal>.
|
||||
<literal>org.keycloak.freemarker.ThemeProviderFactory</literal> and <literal>org.keycloak.freemarker.ThemeProvider</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Keycloak comes with two theme providers, one that loads themes from the classpath (used by default themes)
|
||||
@@ -150,12 +163,15 @@
|
||||
<para>
|
||||
The Account SPI allows implementing the account management pages using whatever web framework or templating
|
||||
engine you want. To create an Account provider implement <literal>org.keycloak.account.AccountProviderFactory</literal>
|
||||
and <literal>org.keycloak.account.AccountProvider</literal> in <literal>forms/account-api</literal>.
|
||||
and <literal>org.keycloak.account.AccountProvider</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Keycloaks default account management provider is built on the FreeMarker template engine (<literal>forms/account-freemarker</literal>).
|
||||
To make sure your provider is loaded you will either need to delete <literal>standalone/deployments/auth-server.war/WEB-INF/lib/keycloak-account-freemarker-1.0-beta-4.jar</literal>
|
||||
or disable it with the system property <literal>org.keycloak.account.freemarker.FreeMarkerAccountProviderFactory</literal>.
|
||||
Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal>to specify which provider should be used:
|
||||
<programlisting>
|
||||
"account": {
|
||||
"provider": "custom-provider"
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
<section>
|
||||
@@ -166,9 +182,12 @@
|
||||
and <literal>org.keycloak.login.LoginFormsProvider</literal> in <literal>forms/login-api</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Keycloaks default login forms provider is built on the FreeMarker template engine (<literal>forms/login-freemarker</literal>).
|
||||
To make sure your provider is loaded you will either need to delete <literal>standalone/deployments/auth-server.war/WEB-INF/lib/keycloak-login-freemarker-1.0-beta-4.jar</literal>
|
||||
or disable it with the system property <literal>org.keycloak.login.freemarker.FreeMarkerLoginFormsProviderFactory</literal>.
|
||||
Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal>to specify which provider should be used:
|
||||
<programlisting>
|
||||
"login": {
|
||||
"provider": "custom-provider"
|
||||
}
|
||||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<chapter id="timeouts">
|
||||
<chapter id="timeouts">
|
||||
<title>Cookie settings, Session Timeouts, and Token Lifespans</title>
|
||||
<para>
|
||||
Keycloak has a bunch of fine-grain settings to manage browser cookies, user login sessions, and token lifespans.
|
||||
@@ -43,11 +43,11 @@
|
||||
application not knowing if the user's permissions have changed. This value is usually in minutes.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>Access Code Lifespan</literal> is how long an access code is valid for. An access code is obtained
|
||||
The <literal>Client login timeout</literal> is how long an access code is valid for. An access code is obtained
|
||||
on the 1st leg of the OAuth 2.0 redirection protocol. This should be a short time limit. Usually seconds.
|
||||
</para>
|
||||
<para>
|
||||
The <literal>Access Code Action Lifespan</literal> is how long a user is allowed to attempt a login. When a user tries
|
||||
The <literal>Login user action lifespan</literal> is how long a user is allowed to attempt a login. When a user tries
|
||||
to login, they may have to change their password, set up TOTP, or perform some other action before they are redirected
|
||||
back to your application as an authentnicated user. This value is relatively short and is usually measured in minutes.
|
||||
</para>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
Most of the time when you want to federate an external user store, much of the metadata that would be needed to
|
||||
provide this complete feature set does not exist in that external store. For example your LDAP server may only
|
||||
provide password validation, but not support TOTP or user role mappings. The Keycloak User Federation SPI was
|
||||
written to support these completely variable locations
|
||||
written to support these completely variable configurations.
|
||||
</para>
|
||||
<para>
|
||||
The way user federation works is that Keycloak will import your federated users on demand to its local storage. How
|
||||
@@ -101,7 +101,8 @@
|
||||
<term>Other options</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The rest of the configuration options should be self explanatory.
|
||||
The rest of the configuration options should be self explanatory. You can use tooltips in admin console
|
||||
to see some more details about them.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -109,6 +110,46 @@
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<title>Sync of LDAP users to Keycloak</title>
|
||||
<para>
|
||||
LDAP Federation Provider will automatically take care of synchronization (import) of needed LDAP users into Keycloak database.
|
||||
For example once you first authenticate LDAP user <literal>john</literal> from Keycloak UI, LDAP Federation provider will
|
||||
first import this LDAP user into Keycloak database and then authenticate against LDAP password.
|
||||
</para>
|
||||
<para>
|
||||
Thing is that Federation Provider import just requested users by default, so if you click to <literal>View all users</literal>
|
||||
in Keycloak admin console, you will see just those LDAP users, which were already authenticated/requested by Keycloak.
|
||||
</para>
|
||||
<para>If you want to sync all LDAP users into Keycloak database, you may configure and enable Sync, which is in
|
||||
admin console on same page like the configuration of Federation provider itself. There are 2 types of sync:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Full sync</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This will synchronize all LDAP users into Keycloak DB. Those LDAP users, which already exist in Keycloak and were
|
||||
changed in LDAP directly will be updated in Keycloak DB (For example if user <literal>Mary Kelly</literal> was changed in LDAP to <literal>Mary Doe</literal>).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>Changed users sync</term>
|
||||
<listitem>
|
||||
<para>
|
||||
This will check LDAP and it will sync into Keycloak just those users, which were created or updated in LDAP from the time of last sync.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</para>
|
||||
<para>
|
||||
In usual cases you may want to trigger full sync at the beginning, so you will import all LDAP users to Keycloak just once. Then you may setup
|
||||
periodic sync of changed users, so Keycloak will periodically ask LDAP server for newly created or updated users and backport them to Keycloak DB.
|
||||
Also you may want to trigger full sync again after some longer time or setup periodic full sync as well.
|
||||
</para>
|
||||
<para>In admin console, you can trigger sync directly or you can enable periodic changed or full sync.</para>
|
||||
</section>
|
||||
<section>
|
||||
<title>Writing your own User Federation Provider</title>
|
||||
<para>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<name>Keycloak Audit API</name>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<name>Keycloak Events API</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@@ -19,6 +19,7 @@ public interface Errors {
|
||||
|
||||
String USERNAME_MISSING = "username_missing";
|
||||
String USERNAME_IN_USE = "username_in_use";
|
||||
String EMAIL_IN_USE = "email_in_use";
|
||||
|
||||
String INVALID_REDIRECT_URI = "invalid_redirect_uri";
|
||||
String INVALID_CODE = "invalid_code";
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -10,7 +10,7 @@ public class Event {
|
||||
|
||||
private long time;
|
||||
|
||||
private EventType event;
|
||||
private EventType type;
|
||||
|
||||
private String realmId;
|
||||
|
||||
@@ -34,12 +34,12 @@ public class Event {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public EventType getEvent() {
|
||||
return event;
|
||||
public EventType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setEvent(EventType event) {
|
||||
this.event = event;
|
||||
public void setType(EventType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getRealmId() {
|
||||
@@ -101,7 +101,7 @@ public class Event {
|
||||
public Event clone() {
|
||||
Event clone = new Event();
|
||||
clone.time = time;
|
||||
clone.event = event;
|
||||
clone.type = type;
|
||||
clone.realmId = realmId;
|
||||
clone.clientId = clientId;
|
||||
clone.userId = userId;
|
||||
+25
-25
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ClientModel;
|
||||
@@ -12,14 +12,14 @@ import java.util.List;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class Audit {
|
||||
public class EventBuilder {
|
||||
|
||||
private static final Logger log = Logger.getLogger(Audit.class);
|
||||
private static final Logger log = Logger.getLogger(EventBuilder.class);
|
||||
|
||||
private List<AuditListener> listeners;
|
||||
private List<EventListenerProvider> listeners;
|
||||
private Event event;
|
||||
|
||||
public Audit(List<AuditListener> listeners, RealmModel realm, String ipAddress) {
|
||||
public EventBuilder(List<EventListenerProvider> listeners, RealmModel realm, String ipAddress) {
|
||||
this.listeners = listeners;
|
||||
this.event = new Event();
|
||||
|
||||
@@ -27,60 +27,60 @@ public class Audit {
|
||||
ipAddress(ipAddress);
|
||||
}
|
||||
|
||||
Audit() {
|
||||
EventBuilder() {
|
||||
}
|
||||
|
||||
public Audit realm(RealmModel realm) {
|
||||
public EventBuilder realm(RealmModel realm) {
|
||||
event.setRealmId(realm.getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit realm(String realmId) {
|
||||
public EventBuilder realm(String realmId) {
|
||||
event.setRealmId(realmId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit client(ClientModel client) {
|
||||
public EventBuilder client(ClientModel client) {
|
||||
event.setClientId(client.getClientId());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit client(String clientId) {
|
||||
public EventBuilder client(String clientId) {
|
||||
event.setClientId(clientId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit user(UserModel user) {
|
||||
public EventBuilder user(UserModel user) {
|
||||
event.setUserId(user.getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit user(String userId) {
|
||||
public EventBuilder user(String userId) {
|
||||
event.setUserId(userId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit session(UserSessionModel session) {
|
||||
public EventBuilder session(UserSessionModel session) {
|
||||
event.setSessionId(session.getId());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit session(String sessionId) {
|
||||
public EventBuilder session(String sessionId) {
|
||||
event.setSessionId(sessionId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit ipAddress(String ipAddress) {
|
||||
public EventBuilder ipAddress(String ipAddress) {
|
||||
event.setIpAddress(ipAddress);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit event(EventType e) {
|
||||
event.setEvent(e);
|
||||
public EventBuilder event(EventType e) {
|
||||
event.setType(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit detail(String key, String value) {
|
||||
public EventBuilder detail(String key, String value) {
|
||||
if (value == null || value.equals("")) {
|
||||
return this;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class Audit {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Audit removeDetail(String key) {
|
||||
public EventBuilder removeDetail(String key) {
|
||||
if (event.getDetails() != null) {
|
||||
event.getDetails().remove(key);
|
||||
}
|
||||
@@ -108,19 +108,19 @@ public class Audit {
|
||||
}
|
||||
|
||||
public void error(String error) {
|
||||
event.setEvent(EventType.valueOf(event.getEvent().name() + "_ERROR"));
|
||||
event.setType(EventType.valueOf(event.getType().name() + "_ERROR"));
|
||||
event.setError(error);
|
||||
send();
|
||||
}
|
||||
|
||||
public Audit clone() {
|
||||
Audit clone = new Audit();
|
||||
public EventBuilder clone() {
|
||||
EventBuilder clone = new EventBuilder();
|
||||
clone.listeners = listeners;
|
||||
clone.event = event.clone();
|
||||
return clone;
|
||||
}
|
||||
|
||||
public Audit reset() {
|
||||
public EventBuilder reset() {
|
||||
Event old = event;
|
||||
|
||||
event = new Event();
|
||||
@@ -136,11 +136,11 @@ public class Audit {
|
||||
event.setTime(System.currentTimeMillis());
|
||||
|
||||
if (listeners != null) {
|
||||
for (AuditListener l : listeners) {
|
||||
for (EventListenerProvider l : listeners) {
|
||||
try {
|
||||
l.onEvent(event);
|
||||
} catch (Throwable t) {
|
||||
log.error("Failed to send event to " + l, t);
|
||||
log.error("Failed to send type to " + l, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface AuditListener extends Provider {
|
||||
public interface EventListenerProvider extends Provider {
|
||||
|
||||
public void onEvent(Event event);
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface AuditListenerFactory extends ProviderFactory<AuditListener> {
|
||||
public interface EventListenerProviderFactory extends ProviderFactory<EventListenerProvider> {
|
||||
|
||||
}
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuditProviderSpi implements Spi {
|
||||
public class EventListenerSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "audit";
|
||||
return "eventsListener";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuditProvider.class;
|
||||
return EventListenerProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuditProviderFactory.class;
|
||||
return EventListenerProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.List;
|
||||
*/
|
||||
public interface EventQuery {
|
||||
|
||||
public EventQuery event(EventType... events);
|
||||
public EventQuery type(EventType... types);
|
||||
|
||||
public EventQuery realm(String realmId);
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface AuditProvider extends AuditListener {
|
||||
public interface EventStoreProvider extends EventListenerProvider {
|
||||
|
||||
public EventQuery createQuery();
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface AuditProviderFactory extends ProviderFactory<AuditProvider> {
|
||||
public interface EventStoreProviderFactory extends ProviderFactory<EventStoreProvider> {
|
||||
|
||||
}
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuditListenerSpi implements Spi {
|
||||
public class EventStoreSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "audit-listener";
|
||||
return "eventsStore";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuditListener.class;
|
||||
return EventStoreProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuditListenerFactory.class;
|
||||
return EventStoreProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit;
|
||||
package org.keycloak.events;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@@ -0,0 +1,2 @@
|
||||
org.keycloak.events.EventListenerSpi
|
||||
org.keycloak.events.EventStoreSpi
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-email</artifactId>
|
||||
<name>Keycloak Audit Email Provider</name>
|
||||
<artifactId>keycloak-events-email</artifactId>
|
||||
<name>Keycloak Events Email Provider</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
@@ -27,7 +27,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
+10
-10
@@ -1,14 +1,14 @@
|
||||
package org.keycloak.audit.email;
|
||||
package org.keycloak.events.email;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.email.EmailException;
|
||||
import org.keycloak.email.EmailProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RealmProvider;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -16,16 +16,16 @@ import java.util.Set;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class EmailAuditListener implements AuditListener {
|
||||
public class EmailEventListenerProvider implements EventListenerProvider {
|
||||
|
||||
private static final Logger log = Logger.getLogger(EmailAuditListener.class);
|
||||
private static final Logger log = Logger.getLogger(EmailEventListenerProvider.class);
|
||||
|
||||
private KeycloakSession session;
|
||||
private RealmProvider model;
|
||||
private EmailProvider emailProvider;
|
||||
private Set<EventType> includedEvents;
|
||||
|
||||
public EmailAuditListener(KeycloakSession session, EmailProvider emailProvider, Set<EventType> includedEvents) {
|
||||
public EmailEventListenerProvider(KeycloakSession session, EmailProvider emailProvider, Set<EventType> includedEvents) {
|
||||
this.session = session;
|
||||
this.model = session.realms();
|
||||
this.emailProvider = emailProvider;
|
||||
@@ -34,7 +34,7 @@ public class EmailAuditListener implements AuditListener {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (includedEvents.contains(event.getEvent())) {
|
||||
if (includedEvents.contains(event.getType())) {
|
||||
if (event.getRealmId() != null && event.getUserId() != null) {
|
||||
RealmModel realm = model.getRealm(event.getRealmId());
|
||||
UserModel user = session.users().getUserById(event.getUserId(), realm);
|
||||
@@ -42,7 +42,7 @@ public class EmailAuditListener implements AuditListener {
|
||||
try {
|
||||
emailProvider.setRealm(realm).setUser(user).sendEvent(event);
|
||||
} catch (EmailException e) {
|
||||
log.error("Failed to send event mail", e);
|
||||
log.error("Failed to send type mail", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.audit.email;
|
||||
package org.keycloak.events.email;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.AuditListenerFactory;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.EventListenerProviderFactory;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.email.EmailProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.Set;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class EmailAuditListenerFactory implements AuditListenerFactory {
|
||||
public class EmailEventListenerProviderFactory implements EventListenerProviderFactory {
|
||||
|
||||
private static final Set<EventType> SUPPORTED_EVENTS = new HashSet<EventType>();
|
||||
static {
|
||||
@@ -24,9 +24,9 @@ public class EmailAuditListenerFactory implements AuditListenerFactory {
|
||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||
|
||||
@Override
|
||||
public AuditListener create(KeycloakSession session) {
|
||||
public EventListenerProvider create(KeycloakSession session) {
|
||||
EmailProvider emailProvider = session.getProvider(EmailProvider.class);
|
||||
return new EmailAuditListener(session, emailProvider, includedEvents);
|
||||
return new EmailEventListenerProvider(session, emailProvider, includedEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.events.email.EmailEventListenerProviderFactory
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-jboss-logging</artifactId>
|
||||
<name>Keycloak Audit JBoss Logging Provider</name>
|
||||
<artifactId>keycloak-events-jboss-logging</artifactId>
|
||||
<name>Keycloak Events JBoss Logging Provider</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
@@ -32,7 +32,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
+7
-7
@@ -1,19 +1,19 @@
|
||||
package org.keycloak.audit.log;
|
||||
package org.keycloak.events.log;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.Event;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JBossLoggingAuditListener implements AuditListener {
|
||||
public class JBossLoggingEventListenerProvider implements EventListenerProvider {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public JBossLoggingAuditListener(Logger logger) {
|
||||
public JBossLoggingEventListenerProvider(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ public class JBossLoggingAuditListener implements AuditListener {
|
||||
if (logger.isEnabled(level)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("event=");
|
||||
sb.append(event.getEvent());
|
||||
sb.append("type=");
|
||||
sb.append(event.getType());
|
||||
sb.append(", realmId=");
|
||||
sb.append(event.getRealmId());
|
||||
sb.append(", clientId=");
|
||||
+7
-7
@@ -1,23 +1,23 @@
|
||||
package org.keycloak.audit.log;
|
||||
package org.keycloak.events.log;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditListener;
|
||||
import org.keycloak.audit.AuditListenerFactory;
|
||||
import org.keycloak.events.EventListenerProvider;
|
||||
import org.keycloak.events.EventListenerProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JBossLoggingAuditListenerFactory implements AuditListenerFactory {
|
||||
public class JBossLoggingEventListenerProviderFactory implements EventListenerProviderFactory {
|
||||
|
||||
public static final String ID = "jboss-logging";
|
||||
|
||||
private static final Logger logger = Logger.getLogger("org.keycloak.audit");
|
||||
private static final Logger logger = Logger.getLogger("org.keycloak.events");
|
||||
|
||||
@Override
|
||||
public AuditListener create(KeycloakSession session) {
|
||||
return new JBossLoggingAuditListener(logger);
|
||||
public EventListenerProvider create(KeycloakSession session) {
|
||||
return new JBossLoggingEventListenerProvider(logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.events.log.JBossLoggingEventListenerProviderFactory
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-jpa</artifactId>
|
||||
<name>Keycloak Audit JPA Provider</name>
|
||||
<artifactId>keycloak-events-jpa</artifactId>
|
||||
<name>Keycloak Events Store JPA Provider</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
@@ -33,7 +33,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.audit.jpa;
|
||||
package org.keycloak.events.jpa;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
@@ -19,8 +19,8 @@ public class EventEntity {
|
||||
@Column(name="TIME")
|
||||
private long time;
|
||||
|
||||
@Column(name="EVENT")
|
||||
private String event;
|
||||
@Column(name="TYPE")
|
||||
private String type;
|
||||
|
||||
@Column(name="REALM_ID")
|
||||
private String realmId;
|
||||
@@ -59,12 +59,12 @@ public class EventEntity {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getEvent() {
|
||||
return event;
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setEvent(String event) {
|
||||
this.event = event;
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getRealmId() {
|
||||
+8
-8
@@ -1,8 +1,8 @@
|
||||
package org.keycloak.audit.jpa;
|
||||
package org.keycloak.events.jpa;
|
||||
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventQuery;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventType;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
@@ -37,12 +37,12 @@ public class JpaEventQuery implements EventQuery {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventQuery event(EventType... events) {
|
||||
public EventQuery type(EventType... types) {
|
||||
List<String> eventStrings = new LinkedList<String>();
|
||||
for (EventType e : events) {
|
||||
for (EventType e : types) {
|
||||
eventStrings.add(e.toString());
|
||||
}
|
||||
predicates.add(root.get("event").in(eventStrings));
|
||||
predicates.add(root.get("type").in(eventStrings));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ public class JpaEventQuery implements EventQuery {
|
||||
|
||||
List<Event> events = new LinkedList<Event>();
|
||||
for (EventEntity e : query.getResultList()) {
|
||||
events.add(JpaAuditProvider.convert(e));
|
||||
events.add(JpaEventStoreProvider.convert(e));
|
||||
}
|
||||
|
||||
return events;
|
||||
+11
-11
@@ -1,12 +1,12 @@
|
||||
package org.keycloak.audit.jpa;
|
||||
package org.keycloak.events.jpa;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventQuery;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventType;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
@@ -18,18 +18,18 @@ import java.util.UUID;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JpaAuditProvider implements AuditProvider {
|
||||
public class JpaEventStoreProvider implements EventStoreProvider {
|
||||
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
private static final TypeReference<Map<String, String>> mapType = new TypeReference<Map<String, String>>() {
|
||||
};
|
||||
private static final Logger logger = Logger.getLogger(JpaAuditProvider.class);
|
||||
private static final Logger logger = Logger.getLogger(JpaEventStoreProvider.class);
|
||||
|
||||
private EntityManager em;
|
||||
private EntityTransaction tx;
|
||||
private Set<EventType> includedEvents;
|
||||
|
||||
public JpaAuditProvider(EntityManager em, Set<EventType> includedEvents) {
|
||||
public JpaEventStoreProvider(EntityManager em, Set<EventType> includedEvents) {
|
||||
this.em = em;
|
||||
this.includedEvents = includedEvents;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class JpaAuditProvider implements AuditProvider {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (includedEvents.contains(event.getEvent())) {
|
||||
if (includedEvents.contains(event.getType())) {
|
||||
em.persist(convert(event));
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class JpaAuditProvider implements AuditProvider {
|
||||
EventEntity e = new EventEntity();
|
||||
e.setId(UUID.randomUUID().toString());
|
||||
e.setTime(o.getTime());
|
||||
e.setEvent(o.getEvent().toString());
|
||||
e.setType(o.getType().toString());
|
||||
e.setRealmId(o.getRealmId());
|
||||
e.setClientId(o.getClientId());
|
||||
e.setUserId(o.getUserId());
|
||||
@@ -87,7 +87,7 @@ public class JpaAuditProvider implements AuditProvider {
|
||||
static Event convert(EventEntity o) {
|
||||
Event e = new Event();
|
||||
e.setTime(o.getTime());
|
||||
e.setEvent(EventType.valueOf(o.getEvent()));
|
||||
e.setType(EventType.valueOf(o.getType()));
|
||||
e.setRealmId(o.getRealmId());
|
||||
e.setClientId(o.getClientId());
|
||||
e.setUserId(o.getUserId());
|
||||
+7
-7
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.audit.jpa;
|
||||
package org.keycloak.events.jpa;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventStoreProviderFactory;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.connections.jpa.JpaConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
@@ -13,16 +13,16 @@ import java.util.Set;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JpaAuditProviderFactory implements AuditProviderFactory {
|
||||
public class JpaEventStoreProviderFactory implements EventStoreProviderFactory {
|
||||
|
||||
public static final String ID = "jpa";
|
||||
|
||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||
|
||||
@Override
|
||||
public AuditProvider create(KeycloakSession session) {
|
||||
public EventStoreProvider create(KeycloakSession session) {
|
||||
JpaConnectionProvider connection = session.getProvider(JpaConnectionProvider.class);
|
||||
return new JpaAuditProvider(connection.getEntityManager(), includedEvents);
|
||||
return new JpaEventStoreProvider(connection.getEntityManager(), includedEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.events.jpa.JpaEventStoreProviderFactory
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-4</version>
|
||||
<version>1.0.5.Final</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-mongo</artifactId>
|
||||
<name>Keycloak Audit Mongo Provider</name>
|
||||
<artifactId>keycloak-events-mongo</artifactId>
|
||||
<name>Keycloak Events Store Mongo Provider</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
@@ -33,7 +33,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<artifactId>keycloak-events-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
Regular → Executable
+8
-9
@@ -1,15 +1,14 @@
|
||||
package org.keycloak.audit.mongo;
|
||||
package org.keycloak.events.mongo;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBCursor;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventQuery;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventType;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
@@ -27,12 +26,12 @@ public class MongoEventQuery implements EventQuery {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventQuery event(EventType... events) {
|
||||
public EventQuery type(EventType... types) {
|
||||
List<String> eventStrings = new LinkedList<String>();
|
||||
for (EventType e : events) {
|
||||
for (EventType e : types) {
|
||||
eventStrings.add(e.toString());
|
||||
}
|
||||
query.put("event", new BasicDBObject("$in", eventStrings));
|
||||
query.put("type", new BasicDBObject("$in", eventStrings));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -84,7 +83,7 @@ public class MongoEventQuery implements EventQuery {
|
||||
|
||||
List<Event> events = new LinkedList<Event>();
|
||||
while (cur.hasNext()) {
|
||||
events.add(MongoAuditProvider.convert((BasicDBObject) cur.next()));
|
||||
events.add(MongoEventStoreProvider.convert((BasicDBObject) cur.next()));
|
||||
}
|
||||
|
||||
return events;
|
||||
+17
-17
@@ -1,12 +1,12 @@
|
||||
package org.keycloak.audit.mongo;
|
||||
package org.keycloak.events.mongo;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBCollection;
|
||||
import com.mongodb.DBObject;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventQuery;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -15,29 +15,29 @@ import java.util.Set;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class MongoAuditProvider implements AuditProvider {
|
||||
public class MongoEventStoreProvider implements EventStoreProvider {
|
||||
|
||||
private DBCollection audit;
|
||||
private DBCollection events;
|
||||
private Set<EventType> includedEvents;
|
||||
|
||||
public MongoAuditProvider(DBCollection audit, Set<EventType> includedEvents) {
|
||||
this.audit = audit;
|
||||
public MongoEventStoreProvider(DBCollection events, Set<EventType> includedEvents) {
|
||||
this.events = events;
|
||||
this.includedEvents = includedEvents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventQuery createQuery() {
|
||||
return new MongoEventQuery(audit);
|
||||
return new MongoEventQuery(events);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
audit.remove(new BasicDBObject());
|
||||
events.remove(new BasicDBObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(String realmId) {
|
||||
audit.remove(new BasicDBObject("realmId", realmId));
|
||||
events.remove(new BasicDBObject("realmId", realmId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,13 +45,13 @@ public class MongoAuditProvider implements AuditProvider {
|
||||
BasicDBObject q = new BasicDBObject();
|
||||
q.put("realmId", realmId);
|
||||
q.put("time", new BasicDBObject("$lt", olderThan));
|
||||
audit.remove(q);
|
||||
events.remove(q);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
if (includedEvents.contains(event.getEvent())) {
|
||||
audit.insert(convert(event));
|
||||
if (includedEvents.contains(event.getType())) {
|
||||
events.insert(convert(event));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MongoAuditProvider implements AuditProvider {
|
||||
static DBObject convert(Event o) {
|
||||
BasicDBObject e = new BasicDBObject();
|
||||
e.put("time", o.getTime());
|
||||
e.put("event", o.getEvent().toString());
|
||||
e.put("type", o.getType().toString());
|
||||
e.put("realmId", o.getRealmId());
|
||||
e.put("clientId", o.getClientId());
|
||||
e.put("userId", o.getUserId());
|
||||
@@ -84,7 +84,7 @@ public class MongoAuditProvider implements AuditProvider {
|
||||
static Event convert(BasicDBObject o) {
|
||||
Event e = new Event();
|
||||
e.setTime(o.getLong("time"));
|
||||
e.setEvent(EventType.valueOf(o.getString("event")));
|
||||
e.setType(EventType.valueOf(o.getString("type")));
|
||||
e.setRealmId(o.getString("realmId"));
|
||||
e.setClientId(o.getString("clientId"));
|
||||
e.setUserId(o.getString("userId"));
|
||||
+9
-9
@@ -1,12 +1,12 @@
|
||||
package org.keycloak.audit.mongo;
|
||||
package org.keycloak.events.mongo;
|
||||
|
||||
import com.mongodb.DBCollection;
|
||||
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.events.EventStoreProvider;
|
||||
import org.keycloak.events.EventStoreProviderFactory;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.connections.mongo.MongoConnectionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
@@ -16,22 +16,22 @@ import java.util.Set;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class MongoAuditProviderFactory implements AuditProviderFactory {
|
||||
public class MongoEventStoreProviderFactory implements EventStoreProviderFactory {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(MongoAuditProviderFactory.class);
|
||||
protected static final Logger logger = Logger.getLogger(MongoEventStoreProviderFactory.class);
|
||||
|
||||
public static final String ID = "mongo";
|
||||
|
||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||
|
||||
@Override
|
||||
public AuditProvider create(KeycloakSession session) {
|
||||
public EventStoreProvider create(KeycloakSession session) {
|
||||
MongoConnectionProvider connection = session.getProvider(MongoConnectionProvider.class);
|
||||
|
||||
DBCollection collection = connection.getDB().getCollection("audit");
|
||||
DBCollection collection = connection.getDB().getCollection("events");
|
||||
collection.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
||||
|
||||
return new MongoAuditProvider(collection, includedEvents);
|
||||
return new MongoEventStoreProvider(collection, includedEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
Loaded 100 of 657 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user