Compare commits
202
Commits
1.0-rc-1
...
1.0.4.Final
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
5764ad84e9 | ||
|
|
f3fde4a8df | ||
|
|
983ccdd121 | ||
|
|
73ed22c52c |
No files matched your search
@@ -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-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -25,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-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -14,7 +14,7 @@ public class Version {
|
||||
public static String VERSION;
|
||||
public static String BUILD_TIME;
|
||||
public static final String UNKNOWN = "UNKNOWN";
|
||||
public static final Version SINGLETON = new Version();
|
||||
public static final Version SINGLETON;
|
||||
|
||||
private final String version = VERSION;
|
||||
private final String buildTime = BUILD_TIME;
|
||||
@@ -30,6 +30,8 @@ public class Version {
|
||||
VERSION=UNKNOWN;
|
||||
BUILD_TIME=UNKNOWN;
|
||||
}
|
||||
|
||||
SINGLETON = new Version();
|
||||
}
|
||||
|
||||
@JsonProperty("version")
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -60,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;
|
||||
@@ -436,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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.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>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
<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>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
<artifactId>keycloak-js-adapter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<outputDirectory>${project.build.directory}/unpacked/js-adapter</outputDirectory>
|
||||
<includes>*.js</includes>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.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.4.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-rc-1</version>
|
||||
<packaging>jdocbook</packaging>
|
||||
<name>Keycloak Reference Guide (${translation})</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jboss</id>
|
||||
|
||||
@@ -26,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>
|
||||
@@ -38,7 +39,7 @@
|
||||
<bookinfo>
|
||||
<title>Keycloak Reference Guide</title>
|
||||
<subtitle>SSO for Web Apps and REST Services</subtitle>
|
||||
<releaseinfo>1.0-rc-1</releaseinfo>
|
||||
<releaseinfo>&project.version;</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<toc/>
|
||||
@@ -115,10 +116,11 @@ This one is short
|
||||
&CORS;
|
||||
&Timeouts;
|
||||
&AdminApi;
|
||||
&Audit;
|
||||
&Events;
|
||||
&UserFederation;
|
||||
&ExportImport;
|
||||
&ServerCache;
|
||||
&SecurityVulnerabilities;
|
||||
&Migration;
|
||||
|
||||
</book>
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<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>
|
||||
|
||||
@@ -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
|
||||
|
||||
+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>
|
||||
@@ -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-rc-1.zip
|
||||
keycloak-appliance-dist-all-&project.version;.zip
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
keycloak-war-dist-all-1.0-rc-1.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-rc-1/
|
||||
keycloak-appliance-dist-all-&project.version;/
|
||||
keycloak/
|
||||
bin/
|
||||
standalone.sh
|
||||
@@ -42,9 +42,9 @@ keycloak-appliance-dist-all-1.0-rc-1/
|
||||
keycloak-server.json
|
||||
themes/
|
||||
adapters/
|
||||
keycloak-as7-adapter-dist-1.0-rc-1.zip
|
||||
keycloak-eap6-adapter-dist-1.0-rc-1.zip
|
||||
keycloak-wildfly-adapter-dist-1.0-rc-1.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-rc-1/
|
||||
<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-rc-1/
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
keycloak-war-dist-all-1.0-rc-1/
|
||||
keycloak-war-dist-all-&project.version;/
|
||||
deployments/
|
||||
auth-server.war/
|
||||
keycloak-ds.xml
|
||||
@@ -87,9 +87,9 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
keycloak-server.json
|
||||
themes/
|
||||
adapters/
|
||||
keycloak-as7-adapter-dist-1.0-rc-1.zip
|
||||
keycloak-eap6-adapter-dist-1.0-rc-1.zip
|
||||
keycloak-wildfly-adapter-dist-1.0-rc-1.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,7 +101,7 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
$ cd keycloak-war-dist-all-1.0-rc-1
|
||||
$ cd keycloak-war-dist-all-&project.version;
|
||||
$ cp -r deployments $JBOSS_HOME/standalone
|
||||
$ cp -r configuration $JBOSS_HOME/standalone
|
||||
</programlisting>
|
||||
@@ -129,7 +129,7 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
Configuring keycloak to use a production database.
|
||||
Configuring Keycloak to use a production database.
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
@@ -144,14 +144,14 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
<section>
|
||||
<title>Relational Database Configuration</title>
|
||||
<para>
|
||||
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>
|
||||
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[
|
||||
@@ -180,8 +180,8 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
|
||||
</driver>
|
||||
</drivers>
|
||||
</datasources>
|
||||
</subsystem>
|
||||
</datasources>
|
||||
</subsystem>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -206,16 +206,6 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
]]></programlisting>
|
||||
Possible configuration options are:
|
||||
<variablelist>
|
||||
<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>
|
||||
<varlistentry>
|
||||
<term>dataSource</term>
|
||||
<listitem>
|
||||
@@ -265,6 +255,16 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
</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>
|
||||
@@ -329,7 +329,7 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
in your favourite editor, then change:
|
||||
|
||||
<programlisting><![CDATA[
|
||||
"audit": {
|
||||
"eventsStore": {
|
||||
"provider": "jpa",
|
||||
"jpa": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ]
|
||||
@@ -348,8 +348,11 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
to:
|
||||
|
||||
<programlisting><![CDATA[
|
||||
"audit": {
|
||||
"eventsStore": {
|
||||
"provider": "mongo",
|
||||
"mongo": {
|
||||
"exclude-events": [ "REFRESH_TOKEN" ]
|
||||
}
|
||||
},
|
||||
|
||||
"realm": {
|
||||
@@ -358,7 +361,7 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
|
||||
"user": {
|
||||
"provider": "mongo"
|
||||
}
|
||||
},
|
||||
]]></programlisting>
|
||||
|
||||
And at the end of the file add the snippet like this where you can configure details about your Mongo database:
|
||||
@@ -401,7 +404,7 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
]]>
|
||||
</programlisting>
|
||||
</section>
|
||||
<section>
|
||||
<section id="ssl_modes">
|
||||
<title>SSL/HTTPS Requirement/Modes</title>
|
||||
<warning>
|
||||
<para>
|
||||
@@ -622,29 +625,74 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
<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>
|
||||
@@ -668,17 +716,6 @@ keycloak-war-dist-all-1.0-rc-1/
|
||||
</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
+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>
|
||||
@@ -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-rc-1.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-rc-1.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>
|
||||
|
||||
@@ -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-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.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>
|
||||
+9
-9
@@ -1,9 +1,9 @@
|
||||
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;
|
||||
@@ -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-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.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-rc-1</version>
|
||||
<version>1.0.4.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>
|
||||
+8
-8
@@ -1,11 +1,11 @@
|
||||
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;
|
||||
@@ -26,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;
|
||||
}
|
||||
|
||||
@@ -83,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
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.events.mongo.MongoEventStoreProviderFactory
|
||||
@@ -3,16 +3,16 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<name>Audit Parent</name>
|
||||
<name>Events Parent</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<artifactId>keycloak-events-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
Keycloak Examples
|
||||
=================
|
||||
|
||||
This directory contains a number of examples for Keycloak.
|
||||
|
||||
Demo
|
||||
----
|
||||
|
||||
This is the our main example, which shows Login, Single-Sign On, Single-Sign Out and OAuth Token Grant. The demo comes in two flavours:
|
||||
|
||||
* Preconfigured - Use this flavour to quickly deploy the demo to a local Keycloak server without having to configure anything other than importing the realm settings into Keycloak
|
||||
* Unconfigured - Use this flavour to manually configure and deploy the demo to either a local or external Keycloak server
|
||||
|
||||
For more information look at `preconfigured-demo/README.md` or `unconfigured-demo/README.md`. For the unconfigured-demo there's an accompanying screencast at [http://keycloak.org/docs](http://keycloak.org/docs) that walks you through the setup process.
|
||||
|
||||
|
||||
Cordova
|
||||
-------
|
||||
|
||||
Example Cordova application. For more information look at `cordova/README.md`.
|
||||
|
||||
|
||||
CORS
|
||||
----
|
||||
|
||||
Example CORS application. For more information look at `cors/README.md`.
|
||||
|
||||
|
||||
JS Console
|
||||
----------
|
||||
|
||||
Example JavaScript application that let's you experiment with the JavaScript adapter. For more information look at `js-console/README.md`.
|
||||
|
||||
|
||||
Providers
|
||||
---------
|
||||
|
||||
Example providers for Event Listener SPI, Event Store SPI and User Federation SPI. For more information look at:
|
||||
|
||||
* Event Listener that outputs event detalis to sysout - `providers/event-listener-sysout/README.md`
|
||||
* Event Store that stores events in memory - `providers/event-store-mem/README.md`
|
||||
* User Federation that loads users from a text file - `providers/federation-provider/README.md`
|
||||
|
||||
|
||||
Themes
|
||||
------
|
||||
|
||||
Example themes to change the look and feel of login forms, account management console and admin console. For more information look at `themes/README.md`.
|
||||
@@ -35,12 +35,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"roleMappings": [
|
||||
{
|
||||
"username": "user",
|
||||
"roles": ["user"]
|
||||
}
|
||||
],
|
||||
"scopeMappings": [
|
||||
{
|
||||
"client": "cordova",
|
||||
@@ -52,17 +46,10 @@
|
||||
"name": "cordova",
|
||||
"enabled": true,
|
||||
"publicClient": true,
|
||||
"redirectUris": []
|
||||
"redirectUris": ["http://localhost"],
|
||||
"webOrigins": ["localhost"]
|
||||
}
|
||||
],
|
||||
"applicationRoleMappings": {
|
||||
"account": [
|
||||
{
|
||||
"username": "user",
|
||||
"roles": ["view-profile", "manage-account"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"applicationScopeMappings": {
|
||||
"account": [
|
||||
{
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
|
||||
<gap:plugin name="org.apache.cordova.inappbrowser" />
|
||||
|
||||
<access origin="http://*"/>
|
||||
<access origin="*"/>
|
||||
</widget>
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
document.addEventListener("deviceready", function() {
|
||||
keycloak.init({ onLoad: 'check-sso' });
|
||||
keycloak.init({ onLoad: 'check-sso' }).success(updateState);
|
||||
}, false);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<h2><span>Realm Roles</span></h2>
|
||||
<button type="submit" data-ng-click="loadRoles()">load Roles</button>
|
||||
@@ -52,6 +53,34 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<h2><span>Social providers</span></h2>
|
||||
<button type="submit" data-ng-click="loadServerInfo()">load available social providers</button>
|
||||
<table class="table" data-ng-show="serverInfo.socialProviders.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Available social providers</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr data-ng-repeat="sp in serverInfo.socialProviders">
|
||||
<td>{{sp}}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<h2><span>Realm info</span></h2>
|
||||
<button type="submit" data-ng-click="loadPublicRealmInfo()">Load public realm info</button>
|
||||
|
||||
<div data-ng-show="realm">
|
||||
Realm name: {{realm.realm}} <br/>
|
||||
Public key: {{realm.public_key}} <br/>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -58,6 +58,20 @@ module.controller('GlobalCtrl', function($scope, $http) {
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.loadServerInfo = function() {
|
||||
$http.get("http://localhost-auth:8080/auth/admin/serverinfo").success(function(data) {
|
||||
$scope.serverInfo = angular.fromJson(data);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.loadPublicRealmInfo = function() {
|
||||
$http.get("http://localhost-auth:8080/auth/realms/cors").success(function(data) {
|
||||
$scope.realm = angular.fromJson(data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.logout = logout;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{
|
||||
"realm": "cors",
|
||||
"enabled": true,
|
||||
"accessTokenLifespan": 3000,
|
||||
"accessCodeLifespan": 10,
|
||||
"accessCodeLifespanUserAction": 6000,
|
||||
"accessTokenLifespan": 60,
|
||||
"accessCodeLifespan": 60,
|
||||
"accessCodeLifespanUserAction": 300,
|
||||
"ssoSessionIdleTimeout": 600,
|
||||
"ssoSessionMaxLifespan": 36000,
|
||||
"sslRequired": "external",
|
||||
"registrationAllowed": false,
|
||||
"social": false,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<name>Examples</name>
|
||||
|
||||
@@ -112,7 +112,7 @@ Next thing you have to do is import the test realm for the demo. Clicking on th
|
||||
create realm page in the Admin UI. The username/password is admin/admin to login in. Keycloak will ask you to
|
||||
create a new admin password before you can go to the create realm page.
|
||||
|
||||
[http://localhost:8080/auth/admin/index.html#/create/realm](http://localhost:8080/auth/admin/index.html#/create/realm)
|
||||
[http://localhost:8080/auth/admin/master/console/#/create/realm](http://localhost:8080/auth/admin/master/console/#/create/realm)
|
||||
|
||||
Import the testrealm.json file that is in the preconfigured-demo/ example directory.
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
Login, Distributed SSO, Distributed Logout, and OAuth Token Grant Examples
|
||||
===================================
|
||||
|
||||
Preconfigured Examples
|
||||
===================================
|
||||
The Preconfigured Examples (in 'preconfigured-demo') contains pre-configured examples that can be deployed without having to configure anything except importing the realm settings into Keycloak. To try this out follow the instructions in preconfigured-demo/README.md.
|
||||
|
||||
Unconfigured Examples
|
||||
===================================
|
||||
The Unconfigured Examples (in 'unconfigured-demo') contains examples without any Keycloak specific configuration. These should be used in conjunction with the online screencasts tutorials at [http://keycloak.org/docs](http://keycloak.org/docs).
|
||||
@@ -1,10 +1,137 @@
|
||||
Unconfigured Examples
|
||||
===================================
|
||||
This set of projects contains a stripped down version of the demo described in preconfigured-demo. All keycloak specific
|
||||
configuration has been removed. Use this project in conjunction with the online screencast tutorials at
|
||||
configuration has been removed. Use this project in conjunction with instructions below and/or the online screencast tutorials at
|
||||
[http://keycloak.org/docs](http://keycloak.org/docs).
|
||||
|
||||
|
||||
# Run Demo with an external Keycloak Server
|
||||
|
||||
These instructions assume you've already installed and started a Keycloak Server. Keycloak can be running on your locally or remotely (for example on OpenShift). If you're not running Keycloak locally you'll also need a locally running WildFly server.
|
||||
|
||||
## Create Realm
|
||||
|
||||
Open the Keycloak admin console and click on `Add Realm`. Enter `demo` as the name for the realm and click `Save`.
|
||||
|
||||
The demo applications uses two realm roles, `user` and `admin`, so the next step is to create these. Click on `Roles` then click on `Add Role`. Use `user` as the role name and click `Save`. Repeat to create a role with the name `admin`.
|
||||
|
||||
Next you'll either want to enable user registration or create a new user.
|
||||
|
||||
### Enable user registration
|
||||
|
||||
To enable user registration first click on `Roles` then `Default Roles`. Select the `user` role and click on the right arrow. This will make sure that all new users are automatically assigned the `user` role. Next step is to enable user registration for the realm. Click on `Settings` then `Login`. Click on the toggle for `user registration` to allow users to self-register.
|
||||
|
||||
### Create user
|
||||
|
||||
To create a new user click on `Users` then `Add User`. You are required to at least fill in the `username` field, but you may want to fill in values for the other fields as well. After you've completed the form click on `Save`. To allow the user to login you also need to set a password for the user. To do this click on `Credentials`. Enter a new password for the user. If you leave the `Temporary` toggle ON the user will be required to reset the password on the next login.
|
||||
|
||||
|
||||
## Deploy Demo Applications
|
||||
|
||||
First you need to install WildFly application server. Second step is to install the Keycloak WildFly subsystem. To do this run:
|
||||
|
||||
# cd <WILDFLY HOME>
|
||||
# unzip <KEYCLOAK DIST>/adapters/keycloak-wildfly-adapter-dist-<KEYCLOAK VERSION>.zip
|
||||
|
||||
Next configure the Keycloak adapter by editing `standalone/configuration/standalone.xml`. Add a new child-element to `<extensions>`:
|
||||
|
||||
<extensions>
|
||||
....
|
||||
<extension module="org.keycloak.keycloak-wildfly-subsystem"/>
|
||||
</extensions>
|
||||
|
||||
You also need to add realm config to the same file. Add a new child-element to `<profile>`:
|
||||
|
||||
<profile>
|
||||
....
|
||||
<subsystem xmlns="urn:jboss:domain:keycloak:1.0">
|
||||
<realm name="demo">
|
||||
<realm-public-key>REALM PUBLIC KEY</realm-public-key>
|
||||
<auth-server-url>KEYCLOAK URL</auth-server-url>
|
||||
<ssl-required>external</ssl-required>
|
||||
</realm>
|
||||
</subsystem>
|
||||
</profile>
|
||||
|
||||
In the above snippet replace the following:
|
||||
|
||||
* `REALM PUBLIC KEY` - replace with the public key for the realm. You can find this in the admin console by selecting the realm, then clicking on `Keys`
|
||||
* `KEYCLOAK URL` - replace with the base url of Keycloak (for example http://localhost:8080/auth or http://keycloak.example.org/auth)
|
||||
|
||||
Don't start the WildFly server until you've configured and deployed the demo applications.
|
||||
|
||||
### Database Services
|
||||
|
||||
Most demo applications connects to the REST services provided by the database-services application, so start with deploying this.
|
||||
|
||||
Run the following to deploy it:
|
||||
|
||||
# cd database-services
|
||||
# mvn install
|
||||
# cp target/database.war <WILDFLY HOME>/standalone/deployments
|
||||
|
||||
Next add the configuration for it to the Keycloak subsystem. Edit `<WILDFLY HOME>/standalone/configuration/standalone.xml` to `<subsystem xmlns="urn:jboss:domain:keycloak:1.0">` add:
|
||||
|
||||
<secure-deployment name="database.war">
|
||||
<realm>demo</realm>
|
||||
<resource>database-service</resource>
|
||||
<bearer-only>true</bearer-only>
|
||||
</secure-deployment>
|
||||
|
||||
### Customer Portal
|
||||
|
||||
Next deploy the customer portal application.
|
||||
|
||||
Run the following to deploy it:
|
||||
|
||||
# cd customer-app
|
||||
# mvn install
|
||||
# cp target/customer-portal.war <WILDFLY HOME>/standalone/deployments
|
||||
|
||||
Then open the Keycloak admin console to add a configuration for it. Navigate to the realm and click on `Applications` then `Add Application`. Fill in the form with:
|
||||
|
||||
* Name - `customer-portal`
|
||||
* Redirect URI - `http://localhost:8080/customer-portal/*` (click `Add` after filling in the field)
|
||||
|
||||
Then click on `Save`. As it's a confidential (non-public) application you need the secret for it. Click on `Credentials` and note the value of the `Secret` field.
|
||||
|
||||
Then edit `<WILDFLY HOME>/standalone/configuration/standalone.xml` and add the following to `<subsystem xmlns="urn:jboss:domain:keycloak:1.0">`:
|
||||
|
||||
<secure-deployment name="customer-portal.war">
|
||||
<realm>demo</realm>
|
||||
<resource>customer-portal</resource>
|
||||
<credential name="secret">APPLICATION SECRET</credential>
|
||||
</secure-deployment>
|
||||
|
||||
In the above snippet replace the following:
|
||||
|
||||
* `APPLICATION SECRET` - replace with the applications secret you just noted from the Keycloak admin console
|
||||
|
||||
### Product Portal
|
||||
|
||||
Next deploy the product portal application.
|
||||
|
||||
Run the following to deploy it:
|
||||
|
||||
# cd product-app
|
||||
# mvn install
|
||||
# cp target/product-portal.war <WILDFLY HOME>/standalone/deployments
|
||||
|
||||
Then open the Keycloak admin console to add a configuration for it. Navigate to the realm and click on `Applications` then `Add Application`. Fill in the form with:
|
||||
|
||||
* Name - `product-portal`
|
||||
* Redirect URI - `http://localhost:8080/product-portal/*` (click `Add` after filling in the field)
|
||||
|
||||
Then click on `Save`. As it's a confidential (non-public) application you need the secret for it. Click on `Credentials` and note the value of the `Secret` field.
|
||||
|
||||
Then edit `<WILDFLY HOME>/standalone/configuration/standalone.xml` and add the following to `<subsystem xmlns="urn:jboss:domain:keycloak:1.0">`:
|
||||
|
||||
<secure-deployment name="product-portal.war">
|
||||
<realm>demo</realm>
|
||||
<resource>product-portal</resource>
|
||||
<credential name="secret">484ba263-8bb5-4048-bb6f-40da75e9eefb</credential>
|
||||
</secure-deployment>
|
||||
|
||||
In the above snippet replace the following:
|
||||
|
||||
* `APPLICATION SECRET` - replace with the applications secret you just noted from the Keycloak admin console
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-rc-1</version>
|
||||
<version>1.0.4.Final</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Loaded 100 of 424 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user