Merge upstream-master into tkyjovsk-master

This commit is contained in:
Tomas Kyjovsky 2015-06-10 10:40:32 +02:00
commit 9dd7a947e9
294 changed files with 4165 additions and 2958 deletions

View file

@ -10,8 +10,8 @@ import org.keycloak.provider.Spi;
public class IdentityProviderMapperSpi implements Spi { public class IdentityProviderMapperSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return false; return true;
} }
@Override @Override

View file

@ -29,7 +29,7 @@ public class IdentityProviderSpi implements Spi {
public static final String IDENTITY_PROVIDER_SPI_NAME = "identity_provider"; public static final String IDENTITY_PROVIDER_SPI_NAME = "identity_provider";
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return false; return false;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class FileConnectionSpi implements Spi { public class FileConnectionSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class HttpClientSpi implements Spi { public class HttpClientSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class InfinispanConnectionSpi implements Spi { public class InfinispanConnectionSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -19,7 +19,7 @@
<column name="AUTH_USER_ID" type="VARCHAR(255)"/> <column name="AUTH_USER_ID" type="VARCHAR(255)"/>
<column name="IP_ADDRESS" type="VARCHAR(255)"/> <column name="IP_ADDRESS" type="VARCHAR(255)"/>
<column name="RESOURCE_PATH" type="VARCHAR(2550)"/> <column name="RESOURCE_PATH" type="VARCHAR(2550)"/>
<column name="REPRESENTATION" type="BLOB(25500)"/> <column name="REPRESENTATION" type="TEXT(25500)"/>
<column name="ERROR" type="VARCHAR(255)"/> <column name="ERROR" type="VARCHAR(255)"/>
</createTable> </createTable>
<createTable tableName="AUTHENTICATOR"> <createTable tableName="AUTHENTICATOR">
@ -28,7 +28,7 @@
</column> </column>
<column name="ALIAS" type="VARCHAR(255)"/> <column name="ALIAS" type="VARCHAR(255)"/>
<column name="REALM_ID" type="VARCHAR(36)"/> <column name="REALM_ID" type="VARCHAR(36)"/>
<column name="PROVIDER_ID" type="VARCHAR(36)"/> <column name="PROVIDER_ID" type="VARCHAR(255)"/>
</createTable> </createTable>
<createTable tableName="AUTHENTICATION_FLOW"> <createTable tableName="AUTHENTICATION_FLOW">
<column name="ID" type="VARCHAR(36)"> <column name="ID" type="VARCHAR(36)">
@ -94,6 +94,9 @@
<column name="ADMIN_EVENTS_DETAILS_ENABLED" type="BOOLEAN" defaultValueBoolean="false"> <column name="ADMIN_EVENTS_DETAILS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/> <constraints nullable="false"/>
</column> </column>
<column name="EDIT_USERNAME_ALLOWED" type="BOOLEAN" defaultValueBoolean="false">
<constraints nullable="false"/>
</column>
</addColumn> </addColumn>
<createTable tableName="CLIENT_SESSION_AUTH_STATUS"> <createTable tableName="CLIENT_SESSION_AUTH_STATUS">
<column name="AUTHENTICATOR" type="VARCHAR(36)"> <column name="AUTHENTICATOR" type="VARCHAR(36)">
@ -107,6 +110,19 @@
<addColumn tableName="CLIENT_SESSION"> <addColumn tableName="CLIENT_SESSION">
<column name="AUTH_USER_ID" type="VARCHAR(36)"/> <column name="AUTH_USER_ID" type="VARCHAR(36)"/>
</addColumn> </addColumn>
<addColumn tableName="IDENTITY_PROVIDER">
<column name="TRUST_EMAIL" type="BOOLEAN" defaultValueBoolean="false"/>
<column name="UPDATE_PROFILE_FIRST_LGN_MD" type="VARCHAR(10)" defaultValue="on">
<constraints nullable="false"/>
</column>
</addColumn>
<!-- migrate value from UPDATE_PROFILE_FIRST_LOGIN to UPDATE_PROFILE_FIRST_LGN_MD then drop it -->
<update tableName="IDENTITY_PROVIDER">
<column name="UPDATE_PROFILE_FIRST_LGN_MD" value="off"/>
<where>UPDATE_PROFILE_FIRST_LOGIN = false</where>
</update>
<dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LOGIN"/>
<addColumn tableName="USER_REQUIRED_ACTION"> <addColumn tableName="USER_REQUIRED_ACTION">
<column name="REQUIRED_ACTION" type="VARCHAR(36)"> <column name="REQUIRED_ACTION" type="VARCHAR(36)">
<constraints nullable="false"/> <constraints nullable="false"/>
@ -147,5 +163,7 @@
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_REALM" referencedColumnNames="ID" referencedTableName="REALM"/> <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
<addForeignKeyConstraint baseColumnNames="FEDERATION_PROVIDER_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_FEDPRV" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_PROVIDER"/> <addForeignKeyConstraint baseColumnNames="FEDERATION_PROVIDER_ID" baseTableName="USER_FEDERATION_MAPPER" constraintName="FK_FEDMAPPERPM_FEDPRV" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_PROVIDER"/>
<addForeignKeyConstraint baseColumnNames="USER_FEDERATION_MAPPER_ID" baseTableName="USER_FEDERATION_MAPPER_CONFIG" constraintName="FK_FEDMAPPER_CFG" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_MAPPER"/> <addForeignKeyConstraint baseColumnNames="USER_FEDERATION_MAPPER_ID" baseTableName="USER_FEDERATION_MAPPER_CONFIG" constraintName="FK_FEDMAPPER_CFG" referencedColumnNames="ID" referencedTableName="USER_FEDERATION_MAPPER"/>
<dropColumn tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED"/>
</changeSet> </changeSet>
</databaseChangeLog> </databaseChangeLog>

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class JpaConnectionSpi implements Spi { public class JpaConnectionSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class JpaUpdaterSpi implements Spi { public class JpaUpdaterSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -6,11 +6,7 @@ import com.mongodb.DBCollection;
import com.mongodb.DBCursor; import com.mongodb.DBCursor;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.connections.mongo.updater.MongoUpdaterProvider; import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
import org.keycloak.connections.mongo.updater.impl.updates.Update; import org.keycloak.connections.mongo.updater.impl.updates.*;
import org.keycloak.connections.mongo.updater.impl.updates.Update1_0_0_Final;
import org.keycloak.connections.mongo.updater.impl.updates.Update1_1_0_Beta1;
import org.keycloak.connections.mongo.updater.impl.updates.Update1_2_0_Beta1;
import org.keycloak.connections.mongo.updater.impl.updates.Update1_2_0_CR1;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import java.util.Date; import java.util.Date;
@ -30,7 +26,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
Update1_0_0_Final.class, Update1_0_0_Final.class,
Update1_1_0_Beta1.class, Update1_1_0_Beta1.class,
Update1_2_0_Beta1.class, Update1_2_0_Beta1.class,
Update1_2_0_CR1.class Update1_2_0_CR1.class,
Update1_3_0_Beta1.class
}; };
@Override @Override

View file

@ -53,6 +53,10 @@ public abstract class Update {
log.debugv("Deleted entries from {0}", collection); log.debugv("Deleted entries from {0}", collection);
} }
protected void removeField(String collection, String field) {
db.getCollection(collection).update(new BasicDBObject(), new BasicDBObject("$unset" , new BasicDBObject(field, 1)), false, true);
}
protected void renameCollection(String collection, String newName) { protected void renameCollection(String collection, String newName) {
db.getCollection(collection).rename(newName); db.getCollection(collection).rename(newName);
} }

View file

@ -0,0 +1,59 @@
package org.keycloak.connections.mongo.updater.impl.updates;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import org.keycloak.models.KeycloakSession;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class Update1_3_0_Beta1 extends Update {
@Override
public String getId() {
return "1.3.0.Beta1";
}
@Override
public void update(KeycloakSession session) {
deleteEntries("clientSessions");
deleteEntries("sessions");
removeField("realms", "passwordCredentialGrantAllowed");
updateIdentityProviders();
}
private void updateIdentityProviders() {
DBCollection realms = db.getCollection("realms");
DBCursor realmsCursor = realms.find();
try {
while (realmsCursor.hasNext()) {
BasicDBObject realm = (BasicDBObject) realmsCursor.next();
BasicDBList identityProviders = (BasicDBList) realm.get("identityProviders");
if (identityProviders != null) {
for (Object ipObj : identityProviders) {
BasicDBObject identityProvider = (BasicDBObject) ipObj;
boolean updateProfileFirstLogin = identityProvider.getBoolean("updateProfileFirstLogin");
String upflMode = updateProfileFirstLogin ? IdentityProviderRepresentation.UPFLM_ON : IdentityProviderRepresentation.UPFLM_OFF;
identityProvider.put("updateProfileFirstLoginMode", upflMode);
identityProvider.removeField("updateProfileFirstLogin");
identityProvider.put("trustEmail", false);
}
}
realms.save(realm);
}
} finally {
realmsCursor.close();
}
}
}

View file

@ -43,7 +43,10 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
"org.keycloak.models.entities.ProtocolMapperEntity", "org.keycloak.models.entities.ProtocolMapperEntity",
"org.keycloak.models.entities.IdentityProviderMapperEntity", "org.keycloak.models.entities.IdentityProviderMapperEntity",
"org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity", "org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity",
"org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity" "org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
"org.keycloak.models.entities.AuthenticationExecutionEntity",
"org.keycloak.models.entities.AuthenticationFlowEntity",
"org.keycloak.models.entities.AuthenticatorEntity",
}; };
private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class); private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class MongoConnectionSpi implements Spi { public class MongoConnectionSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class MongoUpdaterSpi implements Spi { public class MongoUpdaterSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -29,7 +29,26 @@ public class IdentityProviderRepresentation {
protected String internalId; protected String internalId;
protected String providerId; protected String providerId;
protected boolean enabled = true; protected boolean enabled = true;
protected boolean updateProfileFirstLogin = true;
public static final String UPFLM_ON = "on";
public static final String UPFLM_MISSING = "missing";
public static final String UPFLM_OFF = "off";
/**
* Mode of profile update after first login when user is created over this identity provider. Possible values:
* <ul>
* <li><code>on</code> - update profile page is presented for all users
* <li><code>missing</code> - update profile page is presented for users with missing some of mandatory user profile fields
* <li><code>off</code> - update profile page is newer shown after first login
* </ul>
*
* @see #UPFLM_ON
* @see #UPFLM_MISSING
* @see #UPFLM_OFF
*/
protected String updateProfileFirstLoginMode = UPFLM_ON;
protected boolean trustEmail;
protected boolean storeToken; protected boolean storeToken;
protected boolean addReadTokenRoleOnCreate; protected boolean addReadTokenRoleOnCreate;
protected boolean authenticateByDefault; protected boolean authenticateByDefault;
@ -75,12 +94,29 @@ public class IdentityProviderRepresentation {
this.enabled = enabled; this.enabled = enabled;
} }
public boolean isUpdateProfileFirstLogin() { /**
return this.updateProfileFirstLogin; *
* Deprecated because replaced by {@link #updateProfileFirstLoginMode}. Kept here to allow import of old realms.
*
* @deprecated {@link #setUpdateProfileFirstLoginMode(String)}
*/
@Deprecated
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) {
this.updateProfileFirstLoginMode = updateProfileFirstLogin ? UPFLM_ON : UPFLM_OFF;
} }
public void setUpdateProfileFirstLogin(boolean updateProfileFirstLogin) { /**
this.updateProfileFirstLogin = updateProfileFirstLogin; * @return see {@link #updateProfileFirstLoginMode}
*/
public String getUpdateProfileFirstLoginMode() {
return updateProfileFirstLoginMode;
}
/**
* @param updateProfileFirstLoginMode see {@link #updateProfileFirstLoginMode}
*/
public void setUpdateProfileFirstLoginMode(String updateProfileFirstLoginMode) {
this.updateProfileFirstLoginMode = updateProfileFirstLoginMode;
} }
public boolean isAuthenticateByDefault() { public boolean isAuthenticateByDefault() {
@ -106,4 +142,13 @@ public class IdentityProviderRepresentation {
public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) { public void setAddReadTokenRoleOnCreate(boolean addReadTokenRoleOnCreate) {
this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate; this.addReadTokenRoleOnCreate = addReadTokenRoleOnCreate;
} }
public boolean isTrustEmail() {
return trustEmail;
}
public void setTrustEmail(boolean trustEmail) {
this.trustEmail = trustEmail;
}
} }

View file

@ -18,12 +18,14 @@ public class RealmRepresentation {
protected Integer accessCodeLifespanLogin; protected Integer accessCodeLifespanLogin;
protected Boolean enabled; protected Boolean enabled;
protected String sslRequired; protected String sslRequired;
@Deprecated
protected Boolean passwordCredentialGrantAllowed; protected Boolean passwordCredentialGrantAllowed;
protected Boolean registrationAllowed; protected Boolean registrationAllowed;
protected Boolean registrationEmailAsUsername; protected Boolean registrationEmailAsUsername;
protected Boolean rememberMe; protected Boolean rememberMe;
protected Boolean verifyEmail; protected Boolean verifyEmail;
protected Boolean resetPasswordAllowed; protected Boolean resetPasswordAllowed;
protected Boolean editUsernameAllowed;
protected Boolean userCacheEnabled; protected Boolean userCacheEnabled;
protected Boolean realmCacheEnabled; protected Boolean realmCacheEnabled;
@ -268,10 +270,6 @@ public class RealmRepresentation {
return passwordCredentialGrantAllowed; return passwordCredentialGrantAllowed;
} }
public void setPasswordCredentialGrantAllowed(Boolean passwordCredentialGrantAllowed) {
this.passwordCredentialGrantAllowed = passwordCredentialGrantAllowed;
}
public Boolean isRegistrationAllowed() { public Boolean isRegistrationAllowed() {
return registrationAllowed; return registrationAllowed;
} }
@ -328,6 +326,14 @@ public class RealmRepresentation {
this.resetPasswordAllowed = resetPassword; this.resetPasswordAllowed = resetPassword;
} }
public Boolean isEditUsernameAllowed() {
return editUsernameAllowed;
}
public void setEditUsernameAllowed(Boolean editUsernameAllowed) {
this.editUsernameAllowed = editUsernameAllowed;
}
@Deprecated @Deprecated
public Boolean isSocial() { public Boolean isSocial() {
return social; return social;

12
core/src/main/java/org/keycloak/util/HtmlUtils.java Normal file → Executable file
View file

@ -34,7 +34,17 @@ public class HtmlUtils {
for (int i = 0; i < value.length(); i++) { for (int i = 0; i < value.length(); i++) {
char chr = value.charAt(i); char chr = value.charAt(i);
if (chr != '\'' && chr != '"' && chr != '<' && chr != '>' && chr != '/') { if (chr == '<') {
escaped.append("&lt;");
} else if (chr == '>') {
escaped.append("&gt;");
} else if (chr == '"') {
escaped.append("&quot;");
} else if (chr == '\'') {
escaped.append("&apos;");
} else if (chr == '&') {
escaped.append("&amp;");
} else {
escaped.append(chr); escaped.append(chr);
} }
} }

View file

@ -14,7 +14,6 @@
<outputDirectory>keycloak</outputDirectory> <outputDirectory>keycloak</outputDirectory>
<excludes> <excludes>
<exclude>**/*.sh</exclude> <exclude>**/*.sh</exclude>
<exclude>standalone/configuration/standalone-keycloak.xml</exclude>
</excludes> </excludes>
</fileSet> </fileSet>
<fileSet> <fileSet>
@ -25,6 +24,20 @@
</includes> </includes>
<fileMode>0755</fileMode> <fileMode>0755</fileMode>
</fileSet> </fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/keycloak-server-overlay-${project.version}</directory>
<outputDirectory>keycloak</outputDirectory>
<excludes>
<exclude>standalone/configuration/standalone-keycloak.xml</exclude>
</excludes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/keycloak-wf9-adapter-${project.version}</directory>
<outputDirectory>keycloak</outputDirectory>
<excludes>
<exclude>standalone/configuration/standalone-keycloak.xml</exclude>
</excludes>
</fileSet>
<fileSet> <fileSet>
<directory>${project.build.directory}/unpacked/keycloak-docs-${project.version}</directory> <directory>${project.build.directory}/unpacked/keycloak-docs-${project.version}</directory>
<outputDirectory>docs</outputDirectory> <outputDirectory>docs</outputDirectory>
@ -34,5 +47,11 @@
<outputDirectory>examples</outputDirectory> <outputDirectory>examples</outputDirectory>
</fileSet> </fileSet>
</fileSets> </fileSets>
<files>
<file>
<source>${project.build.directory}/unpacked/standalone.xml</source>
<outputDirectory>keycloak/standalone/configuration</outputDirectory>
</file>
</files>
</assembly> </assembly>

View file

@ -16,7 +16,12 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-server-dist</artifactId> <artifactId>keycloak-server-overlay</artifactId>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wf9-adapter-dist</artifactId>
<type>zip</type> <type>zip</type>
</dependency> </dependency>
<dependency> <dependency>
@ -63,7 +68,7 @@
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
<id>unpack-server-overlay</id> <id>unpack-server</id>
<phase>prepare-package</phase> <phase>prepare-package</phase>
<goals> <goals>
<goal>unpack</goal> <goal>unpack</goal>
@ -74,7 +79,24 @@
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-server-overlay</artifactId> <artifactId>keycloak-server-overlay</artifactId>
<type>zip</type> <type>zip</type>
<outputDirectory>${project.build.directory}/unpacked/wildfly-${wildfly.version}</outputDirectory> <outputDirectory>${project.build.directory}/unpacked/keycloak-server-overlay-${project.version}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>unpack-adapter</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wf9-adapter-dist</artifactId>
<type>zip</type>
<outputDirectory>${project.build.directory}/unpacked/keycloak-wf9-adapter-${project.version}</outputDirectory>
</artifactItem> </artifactItem>
</artifactItems> </artifactItems>
</configuration> </configuration>
@ -134,7 +156,7 @@
<includes> <includes>
<include>standalone.xml</include> <include>standalone.xml</include>
</includes> </includes>
<outputDir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</outputDir> <outputDir>${project.build.directory}/unpacked/</outputDir>
</transformationSet> </transformationSet>
</transformationSets> </transformationSets>
</configuration> </configuration>

View file

@ -1,72 +0,0 @@
{
"admin": {
"realm": "master"
},
"eventsStore": {
"provider": "jpa",
"jpa": {
"exclude-events": [ "REFRESH_TOKEN" ]
}
},
"realm": {
"provider": "jpa"
},
"user": {
"provider": "jpa"
},
"userSessions": {
"provider" : "mem"
},
"realmCache": {
"provider": "mem"
},
"userCache": {
"provider": "mem",
"mem": {
"maxSize": 20000
}
},
"timer": {
"provider": "basic"
},
"theme": {
"default": "keycloak",
"staticMaxAge": 2592000,
"cacheTemplates": true,
"cacheThemes": true,
"folder": {
"dir": "${jboss.server.config.dir}/themes"
}
},
"login": {
"provider": "freemarker"
},
"account": {
"provider": "freemarker"
},
"email": {
"provider": "freemarker"
},
"scheduled": {
"interval": 900
},
"connectionsJpa": {
"default": {
"dataSource": "java:jboss/datasources/KeycloakDS",
"databaseSchema": "update"
}
}
}

View file

@ -1,2 +0,0 @@
Any provider implementation jars and libraries in this folder will be loaded by Keycloak. See the providers
section in the documentation for more details.

View file

@ -1,3 +0,0 @@
Themes to configure the look and feel of login pages and account management console. It's not recommended to
modify existing the built-in themes, instead you should create a new theme that extends a built-in theme. See the theme
section in the documentation for more details.

View file

@ -39,11 +39,9 @@
<xsl:copy> <xsl:copy>
<xsl:apply-templates select="node()|@*"/> <xsl:apply-templates select="node()|@*"/>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1"> <subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<auth-server name="main-auth-server"> <web-context>auth</web-context>
<enabled>true</enabled>
<web-context>auth</web-context>
</auth-server>
</subsystem> </subsystem>
<subsystem xmlns="urn:jboss:domain:keycloak:1.1"/>
</xsl:copy> </xsl:copy>
</xsl:template> </xsl:template>

View file

@ -126,7 +126,7 @@
<version>${project.version}</version> <version>${project.version}</version>
<type>war</type> <type>war</type>
<overWrite>true</overWrite> <overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/${project.build.finalName}/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/auth-server</outputDirectory> <outputDirectory>${project.build.directory}/${project.build.finalName}/modules/system/layers/base/org/keycloak/keycloak-server-subsystem/main/server-war</outputDirectory>
</artifactItem> </artifactItem>
</artifactItems> </artifactItems>
</configuration> </configuration>

View file

@ -4,7 +4,7 @@
<module xmlns="urn:jboss:module:1.1" name="de.idyl.winzipaes"> <module xmlns="urn:jboss:module:1.1" name="de.idyl.winzipaes">
<resources> <resources>
<!-- Insert resources here --> <artifact name="${de.idyl:winzipaes}"/>
</resources> </resources>
<dependencies> <dependencies>
<module name="javax.api"/> <module name="javax.api"/>

View file

@ -25,7 +25,7 @@
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-server-subsystem"> <module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-server-subsystem">
<properties> <properties>
<property name="keycloak-version" value="${project.version}"/> <property name="keycloak-version" value="${project.version}"/>
<property name="auth-server-exploded" value="false"/> <property name="server-war-exploded" value="false"/>
</properties> </properties>
<resources> <resources>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="sun.jdk.jgss">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<system export="true">
<paths>
<path name="sun/security/jgss" />
<path name="sun/security/jgss/spi" />
<path name="sun/security/jgss/krb5" />
</paths>
</system>
</dependencies>
</module>

View file

@ -46,11 +46,6 @@
<maven-resource group="net.iharder" artifact="base64"/> <maven-resource group="net.iharder" artifact="base64"/>
</module-def> </module-def>
<module-def name="org.bouncycastle">
<maven-resource group="org.bouncycastle" artifact="bcprov-jdk15on"/>
<maven-resource group="org.bouncycastle" artifact="bcpkix-jdk15on"/>
</module-def>
<module-def name="org.keycloak.keycloak-broker-core"> <module-def name="org.keycloak.keycloak-broker-core">
<maven-resource group="org.keycloak" artifact="keycloak-broker-core"/> <maven-resource group="org.keycloak" artifact="keycloak-broker-core"/>
</module-def> </module-def>
@ -71,10 +66,6 @@
<maven-resource group="org.keycloak" artifact="keycloak-services"/> <maven-resource group="org.keycloak" artifact="keycloak-services"/>
</module-def> </module-def>
<module-def name="org.keycloak.keycloak-wildfly-extensions">
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-extensions"/>
</module-def>
<module-def name="com.google.zxing.core"> <module-def name="com.google.zxing.core">
<maven-resource group="com.google.zxing" artifact="core"/> <maven-resource group="com.google.zxing" artifact="core"/>
</module-def> </module-def>
@ -315,40 +306,9 @@
<module-def name="org.keycloak.keycloak-server"></module-def> <module-def name="org.keycloak.keycloak-server"></module-def>
<module-def name="org.keycloak.keycloak-adapter-core">
<maven-resource group="org.keycloak" artifact="keycloak-adapter-core"/>
</module-def>
<module-def name="org.keycloak.keycloak-jboss-adapter-core">
<maven-resource group="org.keycloak" artifact="keycloak-jboss-adapter-core"/>
</module-def>
<module-def name="org.keycloak.keycloak-as7-adapter">
<maven-resource group="org.keycloak" artifact="keycloak-as7-adapter"/>
<maven-resource group="org.keycloak" artifact="keycloak-tomcat-core-adapter"/>
</module-def>
<module-def name="org.keycloak.keycloak-undertow-adapter">
<maven-resource group="org.keycloak" artifact="keycloak-undertow-adapter"/>
</module-def>
<module-def name="org.keycloak.keycloak-wildfly-adapter">
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter"/>
</module-def>
<module-def name="org.keycloak.keycloak-server-subsystem"> <module-def name="org.keycloak.keycloak-server-subsystem">
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-server-subsystem"/> <maven-resource group="org.keycloak" artifact="keycloak-wildfly-server-subsystem"/>
</module-def> </module-def>
<module-def name="org.keycloak.keycloak-as7-subsystem">
<maven-resource group="org.keycloak" artifact="keycloak-as7-subsystem"/>
</module-def>
<module-def name="org.apache.httpcomponents" slot="4.3">
<maven-resource group="org.apache.httpcomponents" artifact="httpclient"/>
<maven-resource group="org.apache.httpcomponents" artifact="httpcore"/>
<maven-resource group="org.apache.httpcomponents" artifact="httpmime"/>
</module-def>
</target> </target>
<target name="clean-target"> <target name="clean-target">

View file

@ -34,26 +34,6 @@
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-core-jaxrs</artifactId> <artifactId>keycloak-core-jaxrs</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jboss-adapter-core</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-adapter</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-server-subsystem</artifactId> <artifactId>keycloak-wildfly-server-subsystem</artifactId>
@ -64,18 +44,6 @@
<artifactId>keycloak-server</artifactId> <artifactId>keycloak-server</artifactId>
<type>war</type> <type>war</type>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-subsystem</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.apache.httpcomponents" slot="4.3">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.apache.commons.codec"/>
<module name="org.apache.commons.logging"/>
<module name="org.apache.james.mime4j"/>
</dependencies>
</module>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.bouncycastle">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-core">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
<module name="org.codehaus.jackson.jackson-xc"/>
<module name="org.apache.httpcomponents" slot="4.3" />
<module name="org.jboss.logging"/>
<module name="org.keycloak.keycloak-core"/>
<module name="net.iharder.base64"/>
</dependencies>
</module>

View file

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014, Red Hat, Inc., and individual contributors
~ as indicated by the @author tags. See the copyright.txt file in the
~ distribution for a full listing of individual contributors.
~
~ This is free software; you can redistribute it and/or modify it
~ under the terms of the GNU Lesser General Public License as
~ published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~
~ This software is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public
~ License along with this software; if not, write to the Free
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-adapter-subsystem">
<properties>
<property name="keycloak-version" value="${project.version}"/>
</properties>
<resources>
<resource-root path="."/>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.jboss.staxmapper"/>
<module name="org.jboss.as.controller"/>
<module name="org.jboss.as.ee"/>
<module name="org.jboss.as.server"/>
<module name="org.jboss.modules"/>
<module name="org.jboss.msc"/>
<module name="org.jboss.logging"/>
<module name="org.jboss.vfs"/>
<module name="org.jboss.as.web-common" optional="true"/>
<module name="org.jboss.as.web" optional="true"/>
<module name="org.jboss.as.version" optional="true"/>
<module name="org.keycloak.keycloak-as7-adapter" optional="true"/>
<module name="org.jboss.metadata"/>
</dependencies>
</module>

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-as7-adapter">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.bouncycastle" />
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
<module name="org.codehaus.jackson.jackson-xc"/>
<module name="org.apache.httpcomponents" slot="4.3" />
<module name="javax.servlet.api"/>
<module name="org.jboss.logging"/>
<module name="org.jboss.as.security"/>
<module name="org.jboss.as.web"/>
<module name="org.picketbox"/>
<module name="org.keycloak.keycloak-adapter-core"/>
<module name="org.keycloak.keycloak-core"/>
</dependencies>
</module>

View file

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-as7-subsystem">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.keycloak.keycloak-as7-adapter"/>
<module name="org.jboss.staxmapper"/>
<module name="org.jboss.as.controller"/>
<module name="org.jboss.as.server"/>
<module name="org.jboss.as.web"/>
<module name="org.jboss.modules"/>
<module name="org.jboss.msc"/>
<module name="org.jboss.logging"/>
<module name="org.jboss.vfs"/>
<module name="org.jboss.metadata"/>
</dependencies>
</module>

View file

@ -14,7 +14,7 @@
<module name="org.keycloak.keycloak-model-api"/> <module name="org.keycloak.keycloak-model-api"/>
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="javax.api"/> <module name="javax.api"/>
<module name="org.apache.httpcomponents" slot="4.3" /> <module name="org.apache.httpcomponents"/>
</dependencies> </dependencies>
</module> </module>

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-jboss-adapter-core">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.jboss.logging"/>
<module name="org.picketbox"/>
<module name="org.keycloak.keycloak-adapter-core"/>
<module name="org.keycloak.keycloak-core"/>
</dependencies>
</module>

View file

@ -16,7 +16,7 @@
<module name="org.keycloak.keycloak-login-api"/> <module name="org.keycloak.keycloak-login-api"/>
<module name="org.keycloak.keycloak-services"/> <module name="org.keycloak.keycloak-services"/>
<module name="org.keycloak.keycloak-forms-common-freemarker"/> <module name="org.keycloak.keycloak-forms-common-freemarker"/>
<module name="org.apache.httpcomponents" slot="4.3" /> <module name="org.apache.httpcomponents"/>
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="javax.ws.rs.api"/> <module name="javax.ws.rs.api"/>
<module name="org.jboss.resteasy.resteasy-jaxrs"/> <module name="org.jboss.resteasy.resteasy-jaxrs"/>

View file

@ -46,7 +46,6 @@
<module name="org.jboss.as.web-common" optional="true"/> <module name="org.jboss.as.web-common" optional="true"/>
<module name="org.jboss.as.web" optional="true"/> <module name="org.jboss.as.web" optional="true"/>
<module name="org.jboss.as.version" optional="true"/> <module name="org.jboss.as.version" optional="true"/>
<module name="org.keycloak.keycloak-as7-adapter" optional="true"/>
<module name="org.jboss.metadata"/> <module name="org.jboss.metadata"/>
</dependencies> </dependencies>
</module> </module>

View file

@ -9,10 +9,6 @@
<dependencies> <dependencies>
<module name="org.keycloak.keycloak-account-api" services="import"/> <module name="org.keycloak.keycloak-account-api" services="import"/>
<module name="org.keycloak.keycloak-account-freemarker" services="import"/> <module name="org.keycloak.keycloak-account-freemarker" services="import"/>
<module name="org.keycloak.keycloak-adapter-core" services="import"/>
<module name="org.keycloak.keycloak-adapter-subsystem" services="import"/>
<module name="org.keycloak.keycloak-as7-adapter" services="import"/>
<module name="org.keycloak.keycloak-as7-subsystem" services="import"/>
<module name="org.keycloak.keycloak-connections-infinispan" services="import"/> <module name="org.keycloak.keycloak-connections-infinispan" services="import"/>
<module name="org.keycloak.keycloak-connections-jpa" services="import"/> <module name="org.keycloak.keycloak-connections-jpa" services="import"/>
<module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/> <module name="org.keycloak.keycloak-connections-jpa-liquibase" services="import"/>
@ -36,7 +32,6 @@
<module name="org.keycloak.keycloak-forms-common-themes" services="import"/> <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
<module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/> <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
<module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/> <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
<module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
<module name="org.keycloak.keycloak-js-adapter" services="import"/> <module name="org.keycloak.keycloak-js-adapter" services="import"/>
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/> <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
<module name="org.keycloak.keycloak-ldap-federation" services="import"/> <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
@ -61,8 +56,6 @@
<module name="org.keycloak.keycloak-server-subsystem" services="import"/> <module name="org.keycloak.keycloak-server-subsystem" services="import"/>
<module name="org.keycloak.keycloak-timer-api" services="import"/> <module name="org.keycloak.keycloak-timer-api" services="import"/>
<module name="org.keycloak.keycloak-timer-basic" services="import"/> <module name="org.keycloak.keycloak-timer-basic" services="import"/>
<module name="org.keycloak.keycloak-undertow-adapter" services="import"/>
<module name="org.keycloak.keycloak-wildfly-adapter" services="import"/>
</dependencies> </dependencies>
</module> </module>

View file

@ -36,7 +36,6 @@
<module name="org.keycloak.keycloak-forms-common-themes" services="import"/> <module name="org.keycloak.keycloak-forms-common-themes" services="import"/>
<module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/> <module name="org.keycloak.keycloak-invalidation-cache-infinispan" services="import"/>
<module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/> <module name="org.keycloak.keycloak-invalidation-cache-model" services="import"/>
<module name="org.keycloak.keycloak-jboss-adapter-core" services="import"/>
<module name="org.keycloak.keycloak-js-adapter" services="import"/> <module name="org.keycloak.keycloak-js-adapter" services="import"/>
<module name="org.keycloak.keycloak-kerberos-federation" services="import"/> <module name="org.keycloak.keycloak-kerberos-federation" services="import"/>
<module name="org.keycloak.keycloak-ldap-federation" services="import"/> <module name="org.keycloak.keycloak-ldap-federation" services="import"/>
@ -50,7 +49,6 @@
<module name="org.keycloak.keycloak-model-sessions-jpa" services="import"/> <module name="org.keycloak.keycloak-model-sessions-jpa" services="import"/>
<module name="org.keycloak.keycloak-model-sessions-mem" services="import"/> <module name="org.keycloak.keycloak-model-sessions-mem" services="import"/>
<module name="org.keycloak.keycloak-model-sessions-mongo" services="import"/> <module name="org.keycloak.keycloak-model-sessions-mongo" services="import"/>
<module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
<module name="org.keycloak.keycloak-saml-protocol" services="import"/> <module name="org.keycloak.keycloak-saml-protocol" services="import"/>
<module name="org.keycloak.keycloak-services" export="true" services="import"/> <module name="org.keycloak.keycloak-services" export="true" services="import"/>
@ -78,7 +76,7 @@
<module name="net.iharder.base64"/> <module name="net.iharder.base64"/>
<module name="javax.api"/> <module name="javax.api"/>
<module name="javax.activation.api"/> <module name="javax.activation.api"/>
<module name="org.apache.httpcomponents" slot="4.3" /> <module name="org.apache.httpcomponents"/>
</dependencies> </dependencies>
</module> </module>

View file

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-undertow-adapter">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.bouncycastle" />
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
<module name="org.codehaus.jackson.jackson-xc"/>
<module name="org.apache.httpcomponents" slot="4.3" />
<module name="javax.servlet.api"/>
<module name="org.jboss.logging"/>
<module name="org.jboss.xnio"/>
<module name="io.undertow.core"/>
<module name="io.undertow.servlet"/>
<module name="org.keycloak.keycloak-adapter-core"/>
<module name="org.keycloak.keycloak-core"/>
</dependencies>
</module>

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-adapter">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.bouncycastle" />
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
<module name="org.codehaus.jackson.jackson-xc"/>
<module name="org.apache.httpcomponents" slot="4.3" />
<module name="javax.servlet.api"/>
<module name="org.jboss.logging"/>
<module name="io.undertow.core"/>
<module name="io.undertow.servlet"/>
<module name="org.picketbox"/>
<module name="org.keycloak.keycloak-undertow-adapter"/>
<module name="org.keycloak.keycloak-adapter-core"/>
<module name="org.keycloak.keycloak-core"/>
</dependencies>
</module>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-extensions">
<resources>
<!-- Insert resources here -->
</resources>
<dependencies>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-model-api"/>
<module name="org.keycloak.keycloak-services"/>
<module name="org.keycloak.keycloak-forms-common-freemarker"/>
<module name="org.keycloak.keycloak-forms-common-themes"/>
<module name="org.jboss.modules"/>
</dependencies>
</module>

View file

@ -28,13 +28,13 @@
<modules> <modules>
<module>adapters</module> <module>adapters</module>
<!--<module>demo-dist</module>--> <module>demo-dist</module>
<module>docs-dist</module> <module>docs-dist</module>
<module>examples-dist</module> <module>examples-dist</module>
<module>modules</module> <module>modules</module>
<module>proxy-dist</module> <module>proxy-dist</module>
<module>server-dist</module> <module>server-dist</module>
<!--<module>server-overlay</module>--> <module>server-overlay</module>
<module>src-dist</module> <module>src-dist</module>
<module>subsystem-war</module> <module>subsystem-war</module>
<module>feature-packs</module> <module>feature-packs</module>

View file

@ -10,20 +10,38 @@
<fileSets> <fileSets>
<fileSet> <fileSet>
<directory>${project.build.directory}/unpacked/modules</directory> <directory>${project.build.directory}/unpacked/keycloak-${project.version}/modules/system/layers/base</directory>
<outputDirectory>modules</outputDirectory> <outputDirectory>modules/system/layers/base</outputDirectory>
<includes>
<include>com/google/zxing/**</include>
<include>de/idyl/winzipaes/**</include>
<include>net/iharder/**</include>
<include>org/freemarker/**</include>
<include>org/keycloak/**</include>
<include>org/liquibase/**</include>
<include>org/mongodb/**</include>
<include>org/twitter4j/**</include>
<include>sun/jdk/jgss/**</include>
</includes>
</fileSet> </fileSet>
<fileSet> <fileSet>
<directory>${project.build.directory}/unpacked/content</directory> <directory>${project.build.directory}/unpacked/keycloak-${project.version}/content</directory>
<outputDirectory></outputDirectory> <outputDirectory></outputDirectory>
</fileSet> </fileSet>
<fileSet> <fileSet>
<directory>../../forms/common-themes/src/main/resources/theme</directory> <directory>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/themes</directory>
<outputDirectory>standalone/configuration/themes</outputDirectory> <outputDirectory>standalone/configuration/themes</outputDirectory>
<includes> <includes>
<include>**/**</include> <include>**/**</include>
</includes> </includes>
</fileSet> </fileSet>
<fileSet>
<directory>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/providers</directory>
<outputDirectory>standalone/configuration/providers</outputDirectory>
<includes>
<include>**/**</include>
</includes>
</fileSet>
<fileSet> <fileSet>
<directory>../../</directory> <directory>../../</directory>
<includes> <includes>
@ -31,25 +49,19 @@
</includes> </includes>
<outputDirectory></outputDirectory> <outputDirectory></outputDirectory>
</fileSet> </fileSet>
</fileSets> </fileSets>
<files> <files>
<file> <file>
<source>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration/standalone.xml</source> <source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/standalone.xml</source>
<outputDirectory>standalone/configuration</outputDirectory> <outputDirectory>standalone/configuration</outputDirectory>
<destName>standalone-keycloak.xml</destName> <destName>standalone-keycloak.xml</destName>
</file> </file>
<file> <file>
<source>src/main/keycloak-server.json</source> <source>${project.build.directory}/unpacked/keycloak-${project.version}/standalone/configuration/keycloak-server.json</source>
<outputDirectory>standalone/configuration</outputDirectory> <outputDirectory>standalone/configuration</outputDirectory>
</file> </file>
<file>
<source>src/main/themes/README.txt</source>
<outputDirectory>standalone/configuration/themes</outputDirectory>
</file>
<file>
<source>src/main/providers/README.txt</source>
<outputDirectory>standalone/configuration/providers</outputDirectory>
</file>
</files> </files>
</assembly> </assembly>

View file

@ -10,49 +10,27 @@
<artifactId>keycloak-server-overlay</artifactId> <artifactId>keycloak-server-overlay</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Keycloak Server Overlay</name> <name>Keycloak Server Overlay Distribution</name>
<description/> <description/>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-jboss-modules</artifactId> <artifactId>keycloak-server-dist</artifactId>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-dist</artifactId>
<type>zip</type> <type>zip</type>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<finalName>keycloak-overlay-${project.version}</finalName> <finalName>keycloak-overlay-${project.version}</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>unpack-standalone-xml</id> <id>unpack-server-dist</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-dist</artifactId>
<type>zip</type>
<outputDirectory>${project.build.directory}/unpacked</outputDirectory>
</artifactItem>
</artifactItems>
<includes>*/standalone/configuration/standalone.xml</includes>
</configuration>
</execution>
<execution>
<id>unpack-module</id>
<phase>prepare-package</phase> <phase>prepare-package</phase>
<goals> <goals>
<goal>unpack</goal> <goal>unpack</goal>
@ -61,9 +39,9 @@
<artifactItems> <artifactItems>
<artifactItem> <artifactItem>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-jboss-modules</artifactId> <artifactId>keycloak-server-dist</artifactId>
<type>zip</type> <type>zip</type>
<outputDirectory>${project.build.directory}/unpacked/modules</outputDirectory> <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
</artifactItem> </artifactItem>
</artifactItems> </artifactItems>
</configuration> </configuration>
@ -71,32 +49,7 @@
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>xml-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>generate-resources</id>
<phase>package</phase>
<goals>
<goal>transform</goal>
</goals>
<configuration>
<transformationSets>
<transformationSet>
<dir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</dir>
<stylesheet>src/main/xslt/standalone.xsl</stylesheet>
<includes>
<include>standalone.xml</include>
</includes>
<outputDir>${project.build.directory}/unpacked/wildfly-${wildfly.version}/standalone/configuration</outputDir>
</transformationSet>
</transformationSets>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
<executions> <executions>
<execution> <execution>
@ -109,9 +62,11 @@
<descriptors> <descriptors>
<descriptor>assembly.xml</descriptor> <descriptor>assembly.xml</descriptor>
</descriptors> </descriptors>
<outputDirectory>target</outputDirectory> <recompressZippedFiles>true</recompressZippedFiles>
<workDirectory>target/assembly/work</workDirectory> <finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId> <appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode> <tarLongFileMode>gnu</tarLongFileMode>
</configuration> </configuration>
</execution> </execution>

View file

@ -1,72 +0,0 @@
{
"admin": {
"realm": "master"
},
"eventsStore": {
"provider": "jpa",
"jpa": {
"exclude-events": [ "REFRESH_TOKEN" ]
}
},
"realm": {
"provider": "jpa"
},
"user": {
"provider": "jpa"
},
"userSessions": {
"provider" : "mem"
},
"realmCache": {
"provider": "mem"
},
"userCache": {
"provider": "mem",
"mem": {
"maxSize": 20000
}
},
"timer": {
"provider": "basic"
},
"theme": {
"default": "keycloak",
"staticMaxAge": 2592000,
"cacheTemplates": true,
"cacheThemes": true,
"folder": {
"dir": "${jboss.server.config.dir}/themes"
}
},
"login": {
"provider": "freemarker"
},
"account": {
"provider": "freemarker"
},
"email": {
"provider": "freemarker"
},
"scheduled": {
"interval": 900
},
"connectionsJpa": {
"default": {
"dataSource": "java:jboss/datasources/KeycloakDS",
"databaseSchema": "update"
}
}
}

View file

@ -1,2 +0,0 @@
Any provider implementation jars and libraries in this folder will be loaded by Keycloak. See the providers
section in the documentation for more details.

View file

@ -1,3 +0,0 @@
Themes to configure the look and feel of login pages and account management console. It's not recommended to
modify existing the built-in themes, instead you should create a new theme that extends a built-in theme. See the theme
section in the documentation for more details.

View file

@ -1,54 +0,0 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan"
xmlns:j="urn:jboss:domain:3.0"
xmlns:ds="urn:jboss:domain:datasources:3.0"
xmlns:k="urn:jboss:domain:keycloak:1.1"
version="2.0"
exclude-result-prefixes="xalan j ds k">
<xsl:param name="config"/>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
<xsl:strip-space elements="*"/>
<xsl:template match="//j:extensions">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<extension module="org.keycloak.keycloak-server-subsystem"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//ds:datasources">
<xsl:copy>
<xsl:apply-templates select="node()[name(.)='datasource']"/>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<xsl:apply-templates select="node()[name(.)='drivers']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//j:profile">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<subsystem xmlns="urn:jboss:domain:keycloak-server:1.1">
<auth-server name="main-auth-server">
<enabled>true</enabled>
<web-context>auth</web-context>
</auth-server>
</subsystem>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

View file

@ -35,6 +35,7 @@
<!ENTITY UserFederation SYSTEM "modules/user-federation.xml"> <!ENTITY UserFederation SYSTEM "modules/user-federation.xml">
<!ENTITY Kerberos SYSTEM "modules/kerberos.xml"> <!ENTITY Kerberos SYSTEM "modules/kerberos.xml">
<!ENTITY ExportImport SYSTEM "modules/export-import.xml"> <!ENTITY ExportImport SYSTEM "modules/export-import.xml">
<!ENTITY AdminRecovery SYSTEM "modules/admin-recovery.xml">
<!ENTITY ServerCache SYSTEM "modules/cache.xml"> <!ENTITY ServerCache SYSTEM "modules/cache.xml">
<!ENTITY SecurityVulnerabilities SYSTEM "modules/security-vulnerabilities.xml"> <!ENTITY SecurityVulnerabilities SYSTEM "modules/security-vulnerabilities.xml">
<!ENTITY Clustering SYSTEM "modules/clustering.xml"> <!ENTITY Clustering SYSTEM "modules/clustering.xml">
@ -126,6 +127,7 @@ This one is short
&UserFederation; &UserFederation;
&Kerberos; &Kerberos;
&ExportImport; &ExportImport;
&AdminRecovery;
&ServerCache; &ServerCache;
&SAML; &SAML;
&SecurityVulnerabilities; &SecurityVulnerabilities;

View file

@ -79,6 +79,30 @@
<section> <section>
<title>Version specific migration</title> <title>Version specific migration</title>
<section>
<title>Migrating to 1.3.0.Final</title>
<simplesect>
<title>Direct Grant API always enabled</title>
<para>
In the past Direct Grant API (or Resource Owner Password Credentials) was disabled by default and
there was an option on a realm to enable it. The Direct Grant API is now always enabled and the
option to enable/disable for a realm is removed.
</para>
</simplesect>
<simplesect>
<title>Database changed</title>
<para>
There are again few database changes. Remember to backup your database prior to upgrading.
</para>
</simplesect>
<simplesect>
<title>UserFederationProvider changed</title>
<para>
There are few minor changes in UserFederationProvider interface. You may need to sync your implementation when upgrade
to newer version and upgrade few methods, which has changed signature. Changes are really minor, but were needed to improve performance of federation.
</para>
</simplesect>
</section>
<section> <section>
<title>Migrating from 1.2.0.Beta1 to 1.2.0.RC1</title> <title>Migrating from 1.2.0.Beta1 to 1.2.0.RC1</title>
<simplesect> <simplesect>

View file

@ -0,0 +1,15 @@
<chapter id="admin-recovery">
<title>Recovering the Master Admin User</title>
<para>
It is possible for the "admin" user in the master realm to become inoperable. This may be because it was
accidentally deleted, its role mappings were removed, or the password was simply forgotten.
</para>
<para>
To recover the master admin user, just start the server with the following system properties:
<programlisting><![CDATA[
bin/standalone.sh -Dkeycloak.recover-admin=true -Dkeycloak.temp-admin-password=temppassword
]]></programlisting>
Then you can log in to the master admin account with your temporary password. You will then be
prompted to immediately change this password.
</para>
</chapter>

View file

@ -3,8 +3,7 @@
<para> <para>
Keycloak allows you to make direct REST invocations to obtain an access token. Keycloak allows you to make direct REST invocations to obtain an access token.
(See <ulink url="http://tools.ietf.org/html/rfc6749#section-4.3">Resource Owner Password Credentials Grant</ulink> (See <ulink url="http://tools.ietf.org/html/rfc6749#section-4.3">Resource Owner Password Credentials Grant</ulink>
from OAuth 2.0 spec). To use it, Direct Access Grants must be allowed by your realm. This is a configuration switch from OAuth 2.0 spec). To use it you must also have
in the admin console under Settings->General, specifically the "Direct Grant API" switch. You must also have
registered a valid Client to use as the "client_id" for this grant request. registered a valid Client to use as the "client_id" for this grant request.
</para> </para>
<warning> <warning>
@ -12,7 +11,9 @@
It is highly recommended that you do not use Direct Access Grants to write your own login pages for your application. It is highly recommended that you do not use Direct Access Grants to write your own login pages for your application.
You will lose a lot of features that Keycloak has if you do this. Specifically all the account management, remember me, You will lose a lot of features that Keycloak has if you do this. Specifically all the account management, remember me,
lost password, account reset features of Keycloak. Instead, if you want to tailor the look and feel of Keycloak login lost password, account reset features of Keycloak. Instead, if you want to tailor the look and feel of Keycloak login
pages, you should create your own <link linkend="themes">theme</link>. pages, you should create your own <link linkend="themes">theme</link>. There are also security implications
to using Direct Access Grants compared to the redirect based flows as you are exposing plain text passwords
to applications directly.
</para> </para>
<para> <para>
It is even highly recommended that you use the browser to log in for native mobile applications! Android It is even highly recommended that you use the browser to log in for native mobile applications! Android

View file

@ -299,12 +299,24 @@
</entry> </entry>
<entry> <entry>
Allows you to force users to update their profile right after the authentication finishes and Allows you to force users to update their profile right after the authentication finishes and
before the account is actually created in Keycloak. When enabled, users will be presented with the before the account is actually created in Keycloak. When "On", users will be always presented with the
<emphasis>update profile page</emphasis> asking for additional information in order to federate their identities. <emphasis>update profile page</emphasis> asking for additional information in order to federate their identities.
If disabled, the account will be created with the minimal information obtained from the identity provider When "On missing info", users will be presented with the <emphasis>update profile page</emphasis> only if some
mandatory information (email, first name, last name) is not provided by identity provider.
If "Off", the account will be created with the minimal information obtained from the identity provider
during the authentication process. during the authentication process.
</entry> </entry>
</row> </row>
<row>
<entry>
<literal>Trust email</literal>
</entry>
<entry>
Allows you to trust email address returned from the social provider. If enabled then email address returned by the provider
is marked as 'verified' in the Keycloak user profile. This means that email verification step is skipped even
if "Verify email" feature is enabled in realm settings.
</entry>
</row>
<row> <row>
<entry> <entry>
<literal>GUI order</literal> <literal>GUI order</literal>

View file

@ -24,7 +24,8 @@
<section> <section>
<title>LDAP and Active Directory Plugin</title> <title>LDAP and Active Directory Plugin</title>
<para> <para>
Keycloak comes with a built-in LDAP/AD plugin. Currently it is set up only to import username, email, first and last name. Keycloak comes with a built-in LDAP/AD plugin. By default, it is set up only to import username, email, first and last name, but you are free
to configure <link linkend='ldap_mappers'>mappers</link> and add more attributes or delete default ones.
It supports password validation via LDAP/AD protocols and different user metadata synchronization modes. To configure It supports password validation via LDAP/AD protocols and different user metadata synchronization modes. To configure
a federated LDAP store go to the admin console. Click on the <literal>Users</literal> menu option to get you a federated LDAP store go to the admin console. Click on the <literal>Users</literal> menu option to get you
to the user management page. Then click on the <literal>Federation</literal> submenu option. When to the user management page. Then click on the <literal>Federation</literal> submenu option. When
@ -41,7 +42,7 @@
<term>READONLY</term> <term>READONLY</term>
<listitem> <listitem>
<para> <para>
Username, email, first and last name will be unchangable. Keycloak will show an error Username, email, first and last name and other mapped attributes will be unchangeable. Keycloak will show an error
anytime anybody tries to update these fields. Also, password updates will not be supported. anytime anybody tries to update these fields. Also, password updates will not be supported.
</para> </para>
</listitem> </listitem>
@ -50,7 +51,7 @@
<term>WRITABLE</term> <term>WRITABLE</term>
<listitem> <listitem>
<para> <para>
Username, email, first and last name, and passwords can all be updated and will Username, email, first and last name, other mapped attributes and passwords can all be updated and will
be synchronized automatically with your LDAP store. be synchronized automatically with your LDAP store.
</para> </para>
</listitem> </listitem>
@ -158,6 +159,56 @@
</para> </para>
<para>In admin console, you can trigger sync directly or you can enable periodic changed or full sync.</para> <para>In admin console, you can trigger sync directly or you can enable periodic changed or full sync.</para>
</section> </section>
<section id="ldap_mappers">
<title>LDAP/Federation mappers</title>
<para>
LDAP mappers are <literal>listeners</literal>, which are triggered by LDAP Federation provider at various points and provide
another extension point to LDAP integration. They are triggered during import LDAP user into Keycloak, registration Keycloak user back to LDAP or when querying LDAP user from Keycloak.
When you create LDAP Federation provider, Keycloak will automatically provide set of builtin <literal>mappers</literal> for this provider.
You are free to change this set and create new mapper or update/delete existing ones.
</para>
<para>
By default, we have those implementation of LDAP federation mapper:
<variablelist>
<varlistentry>
<term>User Attribute Mapper</term>
<listitem>
<para>
This allows to specify which LDAP attribute is mapped to which attribute of Keycloak User. So for example you can configure
that LDAP attribute <literal>mail</literal> is supposed to be mapped to the UserModel attribute <literal>email</literal> in Keycloak database.
For this mapper implementation, there is always one-to-one mapping (one LDAP attribute mapped to one Keycloak UserModel attribute)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>FullName Mapper</term>
<listitem>
<para>
This allows to specify that fullname of user, which is saved in some LDAP attribute (usualy <literal>cn</literal> ) will be mapped to
<literal>firstName</literal> and <literal>lastname</literal> attributes of UserModel. Having <literal>cn</literal> to contain full name of user
is common case for some LDAP deployments.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Role Mapper</term>
<listitem>
<para>
This allows to configure role mappings from LDAP into Keycloak role mappings. One Role mapper can be used to map LDAP roles
(usually groups from particular branch of LDAP tree) into roles corresponding to either realm roles or client roles of specified client.
It's not a problem to configure more Role mappers for same LDAP provider. So for example you can specify that role mappings from groups under
<literal>ou=main,dc=example,dc=org</literal> will be mapped to realm role mappings and role mappings from
groups under <literal>ou=finance,dc=example,dc=org</literal> will be mapped to client role mappings of client <literal>finance</literal> .
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>By default, there is set of User Attribute mappers to map basic UserModel attributes username, first name, lastname and email to corresponding LDAP attributes. You are free to extend this and provide
more attribute mappings (For example to street, postalCode etc), delete firstName/lastname mapper and put fullName mapper instead, add role mappers etc.
Admin console provides tooltips, which should help on how to configure corresponding mappers.
</para>
</section>
<section> <section>
<title>Writing your own User Federation Provider</title> <title>Writing your own User Federation Provider</title>
<para> <para>

View file

@ -24,5 +24,12 @@ public interface Details {
String NODE_HOST = "node_host"; String NODE_HOST = "node_host";
String REASON = "reason"; String REASON = "reason";
String REVOKED_CLIENT = "revoked_client"; String REVOKED_CLIENT = "revoked_client";
String CLIENT_SESSION_STATE = "client_session_state";
String CLIENT_SESSION_HOST = "client_session_host";
String CONSENT = "consent";
String CONSENT_VALUE_NO_CONSENT_REQUIRED = "no_consent_required"; // No consent is required by client
String CONSENT_VALUE_CONSENT_GRANTED = "consent_granted"; // Consent granted by user
String CONSENT_VALUE_PERSISTED_CONSENT = "persistent_consent"; // Persistent consent used (was already granted by user before)
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class EventListenerSpi implements Spi { public class EventListenerSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return false; return false;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class EventStoreSpi implements Spi { public class EventStoreSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -76,13 +76,17 @@ public class MongoAdminEventQuery implements AdminEventQuery{
@Override @Override
public AdminEventQuery fromTime(Date fromTime) { public AdminEventQuery fromTime(Date fromTime) {
query.put("time", BasicDBObjectBuilder.start("$gte", fromTime.getTime()).get()); BasicDBObject time = query.containsField("time") ? (BasicDBObject) query.get("time") : new BasicDBObject();
time.append("$gte", fromTime.getTime());
query.put("time", time);
return this; return this;
} }
@Override @Override
public AdminEventQuery toTime(Date toTime) { public AdminEventQuery toTime(Date toTime) {
query.put("time", BasicDBObjectBuilder.start("$lte", toTime.getTime()).get()); BasicDBObject time = query.containsField("time") ? (BasicDBObject) query.get("time") : new BasicDBObject();
time.append("$lte", toTime.getTime());
query.put("time", time);
return this; return this;
} }

View file

@ -3,7 +3,6 @@
"enabled": true, "enabled": true,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": true, "registrationAllowed": true,
"passwordCredentialGrantAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ], "requiredCredentials": [ "password" ],

View file

@ -6,7 +6,6 @@
"accessCodeLifespanUserAction": 300, "accessCodeLifespanUserAction": 300,
"ssoSessionIdleTimeout": 600, "ssoSessionIdleTimeout": 600,
"ssoSessionMaxLifespan": 36000, "ssoSessionMaxLifespan": 36000,
"passwordCredentialGrantAllowed": true,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": false, "registrationAllowed": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",

View file

@ -2,7 +2,6 @@
"realm": "twitter-identity-provider-realm", "realm": "twitter-identity-provider-realm",
"enabled": true, "enabled": true,
"sslRequired": "external", "sslRequired": "external",
"passwordCredentialGrantAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"defaultRoles": [ "user" ], "defaultRoles": [ "user" ],

View file

@ -33,7 +33,7 @@ Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
try { try {
list = CustomerDatabaseClient.getCustomers(request); list = CustomerDatabaseClient.getCustomers(request);
} catch (CustomerDatabaseClient.Failure failure) { } catch (CustomerDatabaseClient.Failure failure) {
out.println("There was a failure processing request. You either didn't configure Keycloak properly, or maybe" + out.println("There was a failure processing request. You either didn't configure Keycloak properly, or maybe " +
"you just forgot to secure the database service?"); "you just forgot to secure the database service?");
out.println("Status from database service invocation was: " + failure.getStatus()); out.println("Status from database service invocation was: " + failure.getStatus());
return; return;

View file

@ -6,7 +6,6 @@
"accessCodeLifespanUserAction": 300, "accessCodeLifespanUserAction": 300,
"ssoSessionIdleTimeout": 600, "ssoSessionIdleTimeout": 600,
"ssoSessionMaxLifespan": 36000, "ssoSessionMaxLifespan": 36000,
"passwordCredentialGrantAllowed": true,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": false, "registrationAllowed": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",

View file

@ -6,7 +6,6 @@
"accessCodeLifespanUserAction": 300, "accessCodeLifespanUserAction": 300,
"ssoSessionIdleTimeout": 600, "ssoSessionIdleTimeout": 600,
"ssoSessionMaxLifespan": 36000, "ssoSessionMaxLifespan": 36000,
"passwordCredentialGrantAllowed": true,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": false, "registrationAllowed": false,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",

View file

@ -7,7 +7,6 @@
"accessCodeLifespanUserAction": 6000, "accessCodeLifespanUserAction": 6000,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": false, "registrationAllowed": false,
"passwordCredentialGrantAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ], "requiredCredentials": [ "password" ],

View file

@ -7,7 +7,6 @@
"accessCodeLifespanUserAction": 6000, "accessCodeLifespanUserAction": 6000,
"sslRequired": "external", "sslRequired": "external",
"registrationAllowed": false, "registrationAllowed": false,
"passwordCredentialGrantAllowed": true,
"updateProfileOnInitialSocialLogin": false, "updateProfileOnInitialSocialLogin": false,
"privateKey": "MIICXQIBAAKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQABAoGADwFSvEOQuh0IjWRtKZjwjOo4BrmlbRDJ3rf6x2LoemTttSouXzGxx/H87fSZdxNNuU9HbBHoY4ko4POzmZEWhS0gV6UjM7VArc4YjID6Hh2tfU9vCbuuKZrRs7RjxL70b51WxycKc49PQ4JiR3g04punrpq2UzToPrm66zI+ICECQQD2Jauo6cXXoxHR0QychQf4dityZwFXUoR/8oI/YFiu9XwcWgSMwrFKUdWWNKYmrIRNqCBzrGyeiGdaAjsw41T3AkEAyIpn+XL7bek/uLno5/7ULauf2dFI6MEaHJixQJD7S6Tfo/CGuDK93H4K0GAdjgR0LA0tCnB09yyPCd5NmAYKpQJBAO7+BH4s/PsyScr+vs/6GpMTqXuap6KxbBUO0YfXdEPr9mVQwboqDxmp+0esNua1+n+sDlZBw/TpW+/42p/NGmECQF0sOQyjyH+TfGCmN7j6I7ioYZeA7h/9/9TDeK8n7SmDC8kOanlQUfgMs5eG4JRoK1WANaoA/8cLc9XA7EoynGUCQQDx/Gjg6qyWheVujxjKufH1XkqDNiQHClDRM1ntChCmGq/RmpVmce+mYeOYZ9eofv7UJUCBdamllRlB+056Ld2h", "privateKey": "MIICXQIBAAKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQABAoGADwFSvEOQuh0IjWRtKZjwjOo4BrmlbRDJ3rf6x2LoemTttSouXzGxx/H87fSZdxNNuU9HbBHoY4ko4POzmZEWhS0gV6UjM7VArc4YjID6Hh2tfU9vCbuuKZrRs7RjxL70b51WxycKc49PQ4JiR3g04punrpq2UzToPrm66zI+ICECQQD2Jauo6cXXoxHR0QychQf4dityZwFXUoR/8oI/YFiu9XwcWgSMwrFKUdWWNKYmrIRNqCBzrGyeiGdaAjsw41T3AkEAyIpn+XL7bek/uLno5/7ULauf2dFI6MEaHJixQJD7S6Tfo/CGuDK93H4K0GAdjgR0LA0tCnB09yyPCd5NmAYKpQJBAO7+BH4s/PsyScr+vs/6GpMTqXuap6KxbBUO0YfXdEPr9mVQwboqDxmp+0esNua1+n+sDlZBw/TpW+/42p/NGmECQF0sOQyjyH+TfGCmN7j6I7ioYZeA7h/9/9TDeK8n7SmDC8kOanlQUfgMs5eG4JRoK1WANaoA/8cLc9XA7EoynGUCQQDx/Gjg6qyWheVujxjKufH1XkqDNiQHClDRM1ntChCmGq/RmpVmce+mYeOYZ9eofv7UJUCBdamllRlB+056Ld2h",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDA0oJjgPQJhnVhOo51KauQGfLLreMFu64OJdKXRnfvAQJQTuKNwc5JrR63l/byyW1B6FgclABF818TtLvMCAkn4EuFwQZCZhg3x3+lFGiB/IzC6UAt4Bi0JQrTbdh83/U97GIPegvaDqiqEiQESEkbCZWxM6sh/34hQaAhCaFpMwIDAQAB",

View file

@ -3,7 +3,6 @@
"realm": "saml-demo", "realm": "saml-demo",
"enabled": true, "enabled": true,
"sslRequired": "external", "sslRequired": "external",
"passwordCredentialGrantAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ], "requiredCredentials": [ "password" ],

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class ExportSpi implements Spi { public class ExportSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class ImportSpi implements Spi { public class ImportSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -1,8 +1,6 @@
package org.keycloak.federation.ldap; package org.keycloak.federation.ldap;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
@ -50,7 +48,14 @@ public class LDAPConfig {
} }
public String getUsersDn() { public String getUsersDn() {
return config.get(LDAPConstants.USERS_DN); String usersDn = config.get(LDAPConstants.USERS_DN);
if (usersDn == null) {
// Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
usersDn = config.get("userDnSuffix");
}
return usersDn;
} }
public Collection<String> getUserObjectClasses() { public Collection<String> getUserObjectClasses() {
@ -103,31 +108,13 @@ public class LDAPConfig {
if (uuidAttrName == null) { if (uuidAttrName == null) {
// Differences of unique attribute among various vendors // Differences of unique attribute among various vendors
String vendor = getVendor(); String vendor = getVendor();
if (vendor != null) { uuidAttrName = LDAPConstants.getUuidAttributeName(vendor);
switch (vendor) {
case LDAPConstants.VENDOR_RHDS:
uuidAttrName = "nsuniqueid";
break;
case LDAPConstants.VENDOR_TIVOLI:
uuidAttrName = "uniqueidentifier";
break;
case LDAPConstants.VENDOR_NOVELL_EDIRECTORY:
uuidAttrName = "guid";
break;
case LDAPConstants.VENDOR_ACTIVE_DIRECTORY:
uuidAttrName = LDAPConstants.OBJECT_GUID;
}
}
if (uuidAttrName == null) {
uuidAttrName = LDAPConstants.ENTRY_UUID;
}
} }
return uuidAttrName; return uuidAttrName;
} }
// TODO: Remove and use mapper instead // TODO: Remove and use mapper instead?
public boolean isUserAccountControlsAfterPasswordUpdate() { public boolean isUserAccountControlsAfterPasswordUpdate() {
String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE); String userAccountCtrls = config.get(LDAPConstants.USER_ACCOUNT_CONTROLS_AFTER_PASSWORD_UPDATE);
return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls); return userAccountCtrls==null ? false : Boolean.parseBoolean(userAccountCtrls);
@ -150,6 +137,12 @@ public class LDAPConfig {
String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE); String rdn = config.get(LDAPConstants.RDN_LDAP_ATTRIBUTE);
if (rdn == null) { if (rdn == null) {
rdn = getUsernameLdapAttribute(); rdn = getUsernameLdapAttribute();
if (rdn.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) {
// Just for the backwards compatibility 1.2 -> 1.3 . Should be removed later.
rdn = LDAPConstants.CN;
}
} }
return rdn; return rdn;
} }

View file

@ -308,8 +308,7 @@ public class LDAPFederationProvider implements UserFederationProvider {
@Override @Override
public void preRemove(RealmModel realm, RoleModel role) { public void preRemove(RealmModel realm, RoleModel role) {
// complete I don't think we have to do anything here // TODO: Maybe mappers callback to ensure role deletion propagated to LDAP by RoleLDAPFederationMapper?
// TODO: requires implementation... Maybe mappers callback to ensure role deletion propagated to LDAP by RoleLDAPFederationMapper
} }
public boolean validPassword(RealmModel realm, UserModel user, String password) { public boolean validPassword(RealmModel realm, UserModel user, String password) {

View file

@ -41,7 +41,7 @@ import java.util.Set;
*/ */
public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory { public class LDAPFederationProviderFactory extends UserFederationEventAwareProviderFactory {
private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class); private static final Logger logger = Logger.getLogger(LDAPFederationProviderFactory.class);
public static final String PROVIDER_NAME = "ldap"; public static final String PROVIDER_NAME = LDAPConstants.LDAP_PROVIDER;
private LDAPIdentityStoreRegistry ldapStoreRegistry; private LDAPIdentityStoreRegistry ldapStoreRegistry;
@ -79,7 +79,7 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
// Best effort to create appropriate mappers according to our LDAP config // Best effort to create appropriate mappers according to our LDAP config
@Override @Override
protected void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) { public void onProviderModelCreated(RealmModel realm, UserFederationProviderModel newProviderModel) {
LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig()); LDAPConfig ldapConfig = new LDAPConfig(newProviderModel.getConfig());
boolean activeDirectory = ldapConfig.isActiveDirectory(); boolean activeDirectory = ldapConfig.isActiveDirectory();
@ -94,12 +94,42 @@ public class LDAPFederationProviderFactory extends UserFederationEventAwareProvi
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly); UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel); realm.addUserFederationMapper(mapperModel);
// For AD deployments with sAMAccountName is probably more common to map "cn" to full name of user // CN is typically used as RDN for Active Directory deployments
if (activeDirectory && usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.SAM_ACCOUNT_NAME)) { if (ldapConfig.getRdnLdapAttribute().equalsIgnoreCase(LDAPConstants.CN)) {
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN, if (usernameLdapAttribute.equalsIgnoreCase(LDAPConstants.CN)) {
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel); // For AD deployments with "cn" as username, we will map "givenName" to first name
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
} else {
if (editMode == UserFederationProvider.EditMode.WRITABLE) {
// For AD deployments with "sAMAccountName" as username and writable, we need to map "cn" as username as well (this is needed so we can register new users from KC into LDAP) and we will map "givenName" to first name.
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.GIVENNAME,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("username-cn", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.USERNAME,
UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, LDAPConstants.CN,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
} else {
// For read-only LDAP, we map "cn" as full name
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("full name", newProviderModel.getId(), FullNameLDAPFederationMapperFactory.PROVIDER_ID,
FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE, LDAPConstants.CN,
UserAttributeLDAPFederationMapper.READ_ONLY, readOnly);
realm.addUserFederationMapper(mapperModel);
}
}
} else { } else {
mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID, mapperModel = KeycloakModelUtils.createUserFederationMapperModel("first name", newProviderModel.getId(), UserAttributeLDAPFederationMapperFactory.PROVIDER_ID,
UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME, UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, UserModel.FIRST_NAME,

View file

@ -24,7 +24,7 @@ public class LDAPIdentityStoreRegistry {
// Ldap config might have changed for the realm. In this case, we must re-initialize // Ldap config might have changed for the realm. In this case, we must re-initialize
Map<String, String> config = model.getConfig(); Map<String, String> config = model.getConfig();
if (context == null || !config.equals(context.config)) { if (context == null || !config.equals(context.config)) {
logLDAPConfig(model.getId(), config); logLDAPConfig(model.getDisplayName(), config);
LDAPIdentityStore store = createLdapIdentityStore(config); LDAPIdentityStore store = createLdapIdentityStore(config);
context = new LDAPIdentityStoreContext(config, store); context = new LDAPIdentityStoreContext(config, store);
@ -34,10 +34,10 @@ public class LDAPIdentityStoreRegistry {
} }
// Don't log LDAP password // Don't log LDAP password
private void logLDAPConfig(String fedProviderId, Map<String, String> ldapConfig) { private void logLDAPConfig(String fedProviderDisplayName, Map<String, String> ldapConfig) {
Map<String, String> copy = new HashMap<String, String>(ldapConfig); Map<String, String> copy = new HashMap<String, String>(ldapConfig);
copy.remove(LDAPConstants.BIND_CREDENTIAL); copy.remove(LDAPConstants.BIND_CREDENTIAL);
logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderId + ", LDAP Configuration: " + copy); logger.infof("Creating new LDAP based partition manager for the Federation provider: " + fedProviderDisplayName + ", LDAP Configuration: " + copy);
} }
/** /**
@ -55,23 +55,6 @@ public class LDAPIdentityStoreRegistry {
checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain"); checkSystemProperty("com.sun.jndi.ldap.connect.pool.protocol", "plain");
checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off"); checkSystemProperty("com.sun.jndi.ldap.connect.pool.debug", "off");
/*String ldapLoginNameMapping = ldapConfig.get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
if (ldapLoginNameMapping == null) {
ldapLoginNameMapping = activeDirectory ? LDAPConstants.CN : LDAPConstants.UID;
}
String ldapFirstNameMapping = activeDirectory ? "givenName" : LDAPConstants.CN;
String createTimestampMapping = activeDirectory ? "whenCreated" : LDAPConstants.CREATE_TIMESTAMP;
String modifyTimestampMapping = activeDirectory ? "whenChanged" : LDAPConstants.MODIFY_TIMESTAMP;
String[] userObjectClasses = getUserObjectClasses(ldapConfig); */
/* if (activeDirectory && ldapLoginNameMapping.equals("sAMAccountName")) {
ldapUserMappingConfig.setBindingDnPropertyName("fullName");
ldapUserMappingConfig.addAttributeMapping("fullName", LDAPConstants.CN);
logger.infof("Using 'cn' attribute for DN of user and 'sAMAccountName' for username");
} */
return new LDAPIdentityStore(cfg); return new LDAPIdentityStore(cfg);
} }

View file

@ -45,16 +45,6 @@ public class LDAPUtils {
return ldapUser; return ldapUser;
} }
public static void removeAllUsers(LDAPFederationProvider ldapProvider, RealmModel realm) {
LDAPIdentityStore ldapStore = ldapProvider.getLdapIdentityStore();
LDAPIdentityQuery ldapQuery = LDAPUtils.createQueryForUserSearch(ldapProvider, realm);
List<LDAPObject> allUsers = ldapQuery.getResultList();
for (LDAPObject ldapUser : allUsers) {
ldapStore.remove(ldapUser);
}
}
public static LDAPIdentityQuery createQueryForUserSearch(LDAPFederationProvider ldapProvider, RealmModel realm) { public static LDAPIdentityQuery createQueryForUserSearch(LDAPFederationProvider ldapProvider, RealmModel realm) {
LDAPIdentityQuery ldapQuery = new LDAPIdentityQuery(ldapProvider); LDAPIdentityQuery ldapQuery = new LDAPIdentityQuery(ldapProvider);
LDAPConfig config = ldapProvider.getLdapIdentityStore().getConfig(); LDAPConfig config = ldapProvider.getLdapIdentityStore().getConfig();

View file

@ -1,7 +1,5 @@
package org.keycloak.federation.ldap.idm.query.internal; package org.keycloak.federation.ldap.idm.query.internal;
import java.util.List;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter; import org.keycloak.federation.ldap.idm.query.QueryParameter;

View file

@ -71,11 +71,12 @@ public class LDAPIdentityStore implements IdentityStore {
public void add(LDAPObject ldapObject) { public void add(LDAPObject ldapObject) {
// id will be assigned by the ldap server // id will be assigned by the ldap server
if (ldapObject.getUuid() != null) { if (ldapObject.getUuid() != null) {
throw new IllegalStateException("Can't add object with already assigned uuid"); throw new ModelException("Can't add object with already assigned uuid");
} }
String entryDN = ldapObject.getDn().toString(); String entryDN = ldapObject.getDn().toString();
this.operationManager.createSubContext(entryDN, extractAttributes(ldapObject, true)); BasicAttributes ldapAttributes = extractAttributes(ldapObject, true);
this.operationManager.createSubContext(entryDN, ldapAttributes);
ldapObject.setUuid(getEntryIdentifier(ldapObject)); ldapObject.setUuid(getEntryIdentifier(ldapObject));
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
@ -108,20 +109,20 @@ public class LDAPIdentityStore implements IdentityStore {
@Override @Override
public List<LDAPObject> fetchQueryResults(LDAPIdentityQuery identityQuery) { public List<LDAPObject> fetchQueryResults(LDAPIdentityQuery identityQuery) {
if (identityQuery.getSorting() != null && !identityQuery.getSorting().isEmpty()) {
throw new ModelException("LDAP Identity Store does not yet support sorted queries.");
}
List<LDAPObject> results = new ArrayList<>(); List<LDAPObject> results = new ArrayList<>();
try { try {
if (identityQuery.getSorting() != null && !identityQuery.getSorting().isEmpty()) {
throw new ModelException("LDAP Identity Store does not yet support sorted queries.");
}
String baseDN = identityQuery.getSearchDn(); String baseDN = identityQuery.getSearchDn();
for (Condition condition : identityQuery.getConditions()) { for (Condition condition : identityQuery.getConditions()) {
// Check if we are searching by ID // Check if we are searching by ID
String uuidAttrName = getConfig().getUuidLDAPAttributeName(); String uuidAttrName = getConfig().getUuidLDAPAttributeName();
if (condition.getParameter() != null && condition.getParameter().getName().equals(uuidAttrName)) { if (condition.getParameter() != null && condition.getParameter().getName().equalsIgnoreCase(uuidAttrName)) {
if (EqualCondition.class.isInstance(condition)) { if (EqualCondition.class.isInstance(condition)) {
EqualCondition equalCondition = (EqualCondition) condition; EqualCondition equalCondition = (EqualCondition) condition;
SearchResult search = this.operationManager SearchResult search = this.operationManager
@ -147,7 +148,7 @@ public class LDAPIdentityStore implements IdentityStore {
} }
for (SearchResult result : search) { for (SearchResult result : search) {
if (!result.getNameInNamespace().equals(baseDN)) { if (!result.getNameInNamespace().equalsIgnoreCase(baseDN)) {
results.add(populateAttributedType(result, identityQuery.getReturningReadOnlyLdapAttributes())); results.add(populateAttributedType(result, identityQuery.getReturningReadOnlyLdapAttributes()));
} }
} }
@ -180,8 +181,8 @@ public class LDAPIdentityStore implements IdentityStore {
public boolean validatePassword(LDAPObject user, String password) { public boolean validatePassword(LDAPObject user, String password) {
String userDN = user.getDn().toString(); String userDN = user.getDn().toString();
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debugf("Using DN [%s] for authentication of user", userDN); logger.tracef("Using DN [%s] for authentication of user", userDN);
} }
if (operationManager.authenticate(userDN, password)) { if (operationManager.authenticate(userDN, password)) {
@ -258,7 +259,9 @@ public class LDAPIdentityStore implements IdentityStore {
filter.append(getObjectClassesFilter(identityQuery.getObjectClasses())); filter.append(getObjectClassesFilter(identityQuery.getObjectClasses()));
filter.append(")"); filter.append(")");
logger.infof("Using filter for LDAP search: %s", filter); if (logger.isTraceEnabled()) {
logger.tracef("Using filter for LDAP search: %s . Searching in DN: %s", filter, identityQuery.getSearchDn());
}
return filter; return filter;
} }
@ -278,7 +281,7 @@ public class LDAPIdentityStore implements IdentityStore {
QueryParameter queryParameter = condition.getParameter(); QueryParameter queryParameter = condition.getParameter();
if (!getConfig().getUuidLDAPAttributeName().equals(queryParameter.getName())) { if (!getConfig().getUuidLDAPAttributeName().equalsIgnoreCase(queryParameter.getName())) {
String attributeName = queryParameter.getName(); String attributeName = queryParameter.getName();
if (attributeName != null) { if (attributeName != null) {
@ -377,10 +380,6 @@ public class LDAPIdentityStore implements IdentityStore {
ldapObject.setDn(dn); ldapObject.setDn(dn);
ldapObject.setRdnAttributeName(dn.getFirstRdnAttrName()); ldapObject.setRdnAttributeName(dn.getFirstRdnAttrName());
if (logger.isTraceEnabled()) {
logger.tracef("Populating LDAP Object from DN [%s]", entryDN);
}
NamingEnumeration<? extends Attribute> ldapAttributes = attributes.getAll(); NamingEnumeration<? extends Attribute> ldapAttributes = attributes.getAll();
// Exact name of attributes might be different // Exact name of attributes might be different
@ -400,7 +399,7 @@ public class LDAPIdentityStore implements IdentityStore {
String ldapAttributeName = ldapAttribute.getID(); String ldapAttributeName = ldapAttribute.getID();
if (ldapAttributeName.toLowerCase().equals(getConfig().getUuidLDAPAttributeName().toLowerCase())) { if (ldapAttributeName.equalsIgnoreCase(getConfig().getUuidLDAPAttributeName())) {
Object uuidValue = ldapAttribute.get(); Object uuidValue = ldapAttribute.get();
ldapObject.setUuid(this.operationManager.decodeEntryUUID(uuidValue)); ldapObject.setUuid(this.operationManager.decodeEntryUUID(uuidValue));
} else { } else {
@ -411,12 +410,9 @@ public class LDAPIdentityStore implements IdentityStore {
attrValues.add(attrVal); attrValues.add(attrVal);
} }
if (ldapAttributeName.toLowerCase().equals(LDAPConstants.OBJECT_CLASS)) { if (ldapAttributeName.equalsIgnoreCase(LDAPConstants.OBJECT_CLASS)) {
ldapObject.setObjectClasses(attrValues); ldapObject.setObjectClasses(attrValues);
} else { } else {
if (logger.isTraceEnabled()) {
logger.tracef("Populating ldap attribute [%s] with value [%s] for DN [%s].", ldapAttributeName, attrValues.toString(), entryDN);
}
if (attrValues.size() == 1) { if (attrValues.size() == 1) {
ldapObject.setAttribute(ldapAttributeName, attrValues.iterator().next()); ldapObject.setAttribute(ldapAttributeName, attrValues.iterator().next());
} else { } else {
@ -430,6 +426,9 @@ public class LDAPIdentityStore implements IdentityStore {
} }
} }
if (logger.isTraceEnabled()) {
logger.tracef("Found ldap object [%s] and populated with the attributes [%s]. Read-only attributes are [%s]", ldapObject.getDn().toString(), ldapObject.getAttributes(), ldapObject.getReadOnlyAttributeNames());
}
return ldapObject; return ldapObject;
} catch (Exception e) { } catch (Exception e) {
@ -444,7 +443,7 @@ public class LDAPIdentityStore implements IdentityStore {
for (Map.Entry<String, Object> attrEntry : ldapObject.getAttributes().entrySet()) { for (Map.Entry<String, Object> attrEntry : ldapObject.getAttributes().entrySet()) {
String attrName = attrEntry.getKey(); String attrName = attrEntry.getKey();
Object attrValue = attrEntry.getValue(); Object attrValue = attrEntry.getValue();
if (!ldapObject.getReadOnlyAttributeNames().contains(attrName) && (isCreate || !ldapObject.getRdnAttributeName().equals(attrName))) { if (!ldapObject.getReadOnlyAttributeNames().contains(attrName) && (isCreate || !ldapObject.getRdnAttributeName().equalsIgnoreCase(attrName))) {
if (String.class.isInstance(attrValue)) { if (String.class.isInstance(attrValue)) {
if (attrValue.toString().trim().length() == 0) { if (attrValue.toString().trim().length() == 0) {
@ -461,7 +460,7 @@ public class LDAPIdentityStore implements IdentityStore {
} else if (attrValue == null || attrValue.toString().trim().length() == 0) { } else if (attrValue == null || attrValue.toString().trim().length() == 0) {
entryAttributes.put(attrName, LDAPConstants.EMPTY_ATTRIBUTE_VALUE); entryAttributes.put(attrName, LDAPConstants.EMPTY_ATTRIBUTE_VALUE);
} else { } else {
throw new IllegalArgumentException("Unexpected type of value of argument " + attrName + ". Value is " + attrValue); throw new ModelException("Unexpected type of value of argument " + attrName + ". Value is " + attrValue);
} }
} }
} }
@ -473,10 +472,10 @@ public class LDAPIdentityStore implements IdentityStore {
for (String objectClassValue : ldapObject.getObjectClasses()) { for (String objectClassValue : ldapObject.getObjectClasses()) {
objectClassAttribute.add(objectClassValue); objectClassAttribute.add(objectClassValue);
if (objectClassValue.equals(LDAPConstants.GROUP_OF_NAMES) if (objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_NAMES)
|| objectClassValue.equals(LDAPConstants.GROUP_OF_ENTRIES) || objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_ENTRIES)
|| objectClassValue.equals(LDAPConstants.GROUP_OF_UNIQUE_NAMES)) { || objectClassValue.equalsIgnoreCase(LDAPConstants.GROUP_OF_UNIQUE_NAMES)) {
entryAttributes.put(LDAPConstants.MEMBER, LDAPConstants.EMPTY_ATTRIBUTE_VALUE); entryAttributes.put(LDAPConstants.MEMBER, LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
} }
} }

View file

@ -128,8 +128,8 @@ public class LDAPOperationManager {
execute(new LdapOperation<SearchResult>() { execute(new LdapOperation<SearchResult>() {
@Override @Override
public SearchResult execute(LdapContext context) throws NamingException { public SearchResult execute(LdapContext context) throws NamingException {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debugf("Removing entry with DN [%s]", entryDn); logger.tracef("Removing entry with DN [%s]", entryDn);
} }
destroySubcontext(context, entryDn); destroySubcontext(context, entryDn);
return null; return null;
@ -357,8 +357,8 @@ public class LDAPOperationManager {
public void modifyAttributes(final String dn, final ModificationItem[] mods) { public void modifyAttributes(final String dn, final ModificationItem[] mods) {
try { try {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debugf("Modifying attributes for entry [%s]: [", dn); logger.tracef("Modifying attributes for entry [%s]: [", dn);
for (ModificationItem item : mods) { for (ModificationItem item : mods) {
Object values; Object values;
@ -369,10 +369,10 @@ public class LDAPOperationManager {
values = "No values"; values = "No values";
} }
logger.debugf(" Op [%s]: %s = %s", item.getModificationOp(), item.getAttribute().getID(), values); logger.tracef(" Op [%s]: %s = %s", item.getModificationOp(), item.getAttribute().getID(), values);
} }
logger.debugf("]"); logger.tracef("]");
} }
execute(new LdapOperation<Void>() { execute(new LdapOperation<Void>() {
@ -389,18 +389,18 @@ public class LDAPOperationManager {
public void createSubContext(final String name, final Attributes attributes) { public void createSubContext(final String name, final Attributes attributes) {
try { try {
if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) {
logger.debugf("Creating entry [%s] with attributes: [", name); logger.tracef("Creating entry [%s] with attributes: [", name);
NamingEnumeration<? extends Attribute> all = attributes.getAll(); NamingEnumeration<? extends Attribute> all = attributes.getAll();
while (all.hasMore()) { while (all.hasMore()) {
Attribute attribute = all.next(); Attribute attribute = all.next();
logger.debugf(" %s = %s", attribute.getID(), attribute.get()); logger.tracef(" %s = %s", attribute.getID(), attribute.get());
} }
logger.debugf("]"); logger.tracef("]");
} }
execute(new LdapOperation<Void>() { execute(new LdapOperation<Void>() {
@ -513,7 +513,6 @@ public class LDAPOperationManager {
context = createLdapContext(); context = createLdapContext();
return operation.execute(context); return operation.execute(context);
} catch (NamingException ne) { } catch (NamingException ne) {
logger.error("Could not create Ldap context or operation execution error.", ne);
throw ne; throw ne;
} finally { } finally {
if (context != null) { if (context != null) {

View file

@ -1,24 +1,19 @@
package org.keycloak.federation.ldap.mappers; package org.keycloak.federation.ldap.mappers;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPUtils;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter; import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.EqualCondition; import org.keycloak.federation.ldap.idm.query.internal.EqualCondition;
import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
import org.keycloak.mappers.UserFederationMapper;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderConfigProperty;
/** /**
* Mapper useful for the LDAP deployments when some attribute (usually CN) is mapped to full name of user * Mapper useful for the LDAP deployments when some attribute (usually CN) is mapped to full name of user
@ -35,7 +30,7 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
String ldapFullNameAttrName = getLdapFullNameAttrName(mapperModel); String ldapFullNameAttrName = getLdapFullNameAttrName(mapperModel);
String fullName = ldapUser.getAttributeAsString(ldapFullNameAttrName); String fullName = ldapUser.getAttributeAsString(ldapFullNameAttrName);
fullName = fullName.trim(); fullName = fullName.trim();
if (fullName != null) { if (fullName != null && !fullName.trim().isEmpty()) {
int lastSpaceIndex = fullName.lastIndexOf(" "); int lastSpaceIndex = fullName.lastIndexOf(" ");
if (lastSpaceIndex == -1) { if (lastSpaceIndex == -1) {
user.setLastName(fullName); user.setLastName(fullName);
@ -130,7 +125,7 @@ public class FullNameLDAPFederationMapper extends AbstractLDAPFederationMapper {
fullName = firstNameCondition.getValue() + " " + lastNameCondition.getValue(); fullName = firstNameCondition.getValue() + " " + lastNameCondition.getValue();
} else if (firstNameCondition != null) { } else if (firstNameCondition != null) {
fullName = (String) firstNameCondition.getValue(); fullName = (String) firstNameCondition.getValue();
} else if (firstNameCondition != null) { } else if (lastNameCondition != null) {
fullName = (String) lastNameCondition.getValue(); fullName = (String) lastNameCondition.getValue();
} else { } else {
return; return;

View file

@ -1,14 +1,11 @@
package org.keycloak.federation.ldap.mappers; package org.keycloak.federation.ldap.mappers;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import javax.naming.directory.SearchControls;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.idm.model.LDAPDn; import org.keycloak.federation.ldap.idm.model.LDAPDn;
@ -82,8 +79,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm); RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm);
RoleModel role = roleContainer.getRole(roleName); RoleModel role = roleContainer.getRole(roleName);
// TODO: debug logger.debugf("Granting role [%s] to user [%s] during import from LDAP", roleName, user.getUsername());
logger.infof("Granting role [%s] to user [%s] during import from LDAP", roleName, user.getUsername());
user.grantRole(role); user.grantRole(role);
} }
} }
@ -97,6 +93,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
// Sync roles from LDAP tree and create them in local Keycloak DB (if they don't exist here yet) // Sync roles from LDAP tree and create them in local Keycloak DB (if they don't exist here yet)
protected void syncRolesFromLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, RealmModel realm) { protected void syncRolesFromLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, RealmModel realm) {
if (!rolesSyncedModels.contains(mapperModel.getId())) { if (!rolesSyncedModels.contains(mapperModel.getId())) {
logger.debugf("Syncing roles from LDAP into Keycloak DB. Mapper is [%s], LDAP provider is [%s]", mapperModel.getName(), ldapProvider.getModel().getDisplayName());
LDAPIdentityQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPIdentityQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
// Send query // Send query
@ -108,7 +106,6 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
String roleName = ldapRole.getAttributeAsString(rolesRdnAttr); String roleName = ldapRole.getAttributeAsString(rolesRdnAttr);
if (roleContainer.getRole(roleName) == null) { if (roleContainer.getRole(roleName) == null) {
// TODO: rather change to debug
logger.infof("Syncing role [%s] from LDAP to keycloak DB", roleName); logger.infof("Syncing role [%s] from LDAP to keycloak DB", roleName);
roleContainer.addRole(roleName); roleContainer.addRole(roleName);
} }
@ -127,7 +124,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
String rolesDn = getRolesDn(mapperModel); String rolesDn = getRolesDn(mapperModel);
ldapQuery.setSearchDn(rolesDn); ldapQuery.setSearchDn(rolesDn);
Collection<String> roleObjectClasses = getRoleObjectClasses(mapperModel); Collection<String> roleObjectClasses = getRoleObjectClasses(mapperModel, ldapProvider);
ldapQuery.addObjectClasses(roleObjectClasses); ldapQuery.addObjectClasses(roleObjectClasses);
String rolesRdnAttr = getRoleNameLdapAttribute(mapperModel); String rolesRdnAttr = getRoleNameLdapAttribute(mapperModel);
@ -145,11 +142,11 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
} else { } else {
String clientId = mapperModel.getConfig().get(CLIENT_ID); String clientId = mapperModel.getConfig().get(CLIENT_ID);
if (clientId == null) { if (clientId == null) {
throw new IllegalStateException("Using client roles mapping is requested, but parameter client.id not found!"); throw new ModelException("Using client roles mapping is requested, but parameter client.id not found!");
} }
ClientModel client = realm.getClientByClientId(clientId); ClientModel client = realm.getClientByClientId(clientId);
if (client == null) { if (client == null) {
throw new IllegalStateException("Can't found requested client with clientId: " + clientId); throw new ModelException("Can't found requested client with clientId: " + clientId);
} }
return client; return client;
} }
@ -158,7 +155,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
protected String getRolesDn(UserFederationMapperModel mapperModel) { protected String getRolesDn(UserFederationMapperModel mapperModel) {
String rolesDn = mapperModel.getConfig().get(ROLES_DN); String rolesDn = mapperModel.getConfig().get(ROLES_DN);
if (rolesDn == null) { if (rolesDn == null) {
throw new IllegalStateException("Roles DN is null! Check your configuration"); throw new ModelException("Roles DN is null! Check your configuration");
} }
return rolesDn; return rolesDn;
} }
@ -173,10 +170,11 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
return membershipAttrName!=null ? membershipAttrName : LDAPConstants.MEMBER; return membershipAttrName!=null ? membershipAttrName : LDAPConstants.MEMBER;
} }
protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel) { protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider) {
String objectClasses = mapperModel.getConfig().get(ROLE_OBJECT_CLASSES); String objectClasses = mapperModel.getConfig().get(ROLE_OBJECT_CLASSES);
if (objectClasses == null) { if (objectClasses == null) {
objectClasses = "groupOfNames"; // For Active directory, the default is 'group' . For other servers 'groupOfNames'
objectClasses = ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory() ? LDAPConstants.GROUP : LDAPConstants.GROUP_OF_NAMES;
} }
String[] objClasses = objectClasses.split(","); String[] objClasses = objectClasses.split(",");
@ -192,26 +190,25 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
private Mode getMode(UserFederationMapperModel mapperModel) { private Mode getMode(UserFederationMapperModel mapperModel) {
String modeString = mapperModel.getConfig().get(MODE); String modeString = mapperModel.getConfig().get(MODE);
if (modeString == null || modeString.trim().length() == 0) { if (modeString == null || modeString.isEmpty()) {
return Mode.LDAP_ONLY; throw new ModelException("Mode is missing! Check your configuration");
} }
return Enum.valueOf(Mode.class, modeString.toUpperCase()); return Enum.valueOf(Mode.class, modeString.toUpperCase());
} }
protected LDAPObject createLDAPRole(UserFederationMapperModel mapperModel, String roleName, LDAPFederationProvider ldapProvider) { public LDAPObject createLDAPRole(UserFederationMapperModel mapperModel, String roleName, LDAPFederationProvider ldapProvider) {
LDAPObject ldapObject = new LDAPObject(); LDAPObject ldapObject = new LDAPObject();
String roleNameAttribute = getRoleNameLdapAttribute(mapperModel); String roleNameAttribute = getRoleNameLdapAttribute(mapperModel);
ldapObject.setRdnAttributeName(roleNameAttribute); ldapObject.setRdnAttributeName(roleNameAttribute);
ldapObject.setObjectClasses(getRoleObjectClasses(mapperModel)); ldapObject.setObjectClasses(getRoleObjectClasses(mapperModel, ldapProvider));
ldapObject.setAttribute(roleNameAttribute, roleName); ldapObject.setAttribute(roleNameAttribute, roleName);
LDAPDn roleDn = LDAPDn.fromString(getRolesDn(mapperModel)); LDAPDn roleDn = LDAPDn.fromString(getRolesDn(mapperModel));
roleDn.addFirst(roleNameAttribute, roleName); roleDn.addFirst(roleNameAttribute, roleName);
ldapObject.setDn(roleDn); ldapObject.setDn(roleDn);
// TODO: debug logger.infof("Creating role [%s] to LDAP with DN [%s]", roleName, roleDn.toString());
logger.infof("Creating role to [%s] to LDAP with DN [%s]", roleName, roleDn.toString());
ldapProvider.getLdapIdentityStore().add(ldapObject); ldapProvider.getLdapIdentityStore().add(ldapObject);
return ldapObject; return ldapObject;
} }
@ -233,9 +230,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
Set<String> memberships = getExistingMemberships(mapperModel, ldapRole); Set<String> memberships = getExistingMemberships(mapperModel, ldapRole);
memberships.remove(ldapUser.getDn().toString()); memberships.remove(ldapUser.getDn().toString());
// Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers // Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But on active directory! (Empty membership is not allowed here)
if (memberships.size() == 0) { if (memberships.size() == 0 && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) {
memberships.add(LDAPConstants.EMPTY_ATTRIBUTE_VALUE); memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
} }
ldapRole.setAttribute(getMembershipLdapAttribute(mapperModel), memberships); ldapRole.setAttribute(getMembershipLdapAttribute(mapperModel), memberships);
@ -280,23 +277,6 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
return ldapQuery.getResultList(); return ldapQuery.getResultList();
} }
protected Set<RoleModel> getLDAPRoleMappingsConverted(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, RoleContainerModel roleContainer) {
List<LDAPObject> ldapRoles = getLDAPRoleMappings(mapperModel, ldapProvider, ldapUser);
Set<RoleModel> roles = new HashSet<RoleModel>();
String roleNameLdapAttr = getRoleNameLdapAttribute(mapperModel);
for (LDAPObject role : ldapRoles) {
String roleName = role.getAttributeAsString(roleNameLdapAttr);
RoleModel modelRole = roleContainer.getRole(roleName);
if (modelRole == null) {
// Add role to local DB
modelRole = roleContainer.addRole(roleName);
}
roles.add(modelRole);
}
return roles;
}
@Override @Override
public UserModel proxy(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, UserModel delegate, RealmModel realm) { public UserModel proxy(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, UserModel delegate, RealmModel realm) {
final Mode mode = getMode(mapperModel); final Mode mode = getMode(mapperModel);
@ -323,6 +303,9 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
private final RealmModel realm; private final RealmModel realm;
private final Mode mode; private final Mode mode;
// Avoid loading role mappings from LDAP more times per-request
private Set<RoleModel> cachedLDAPRoleMappings;
public LDAPRoleMappingsUserDelegate(UserModel user, UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, public LDAPRoleMappingsUserDelegate(UserModel user, UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser,
RealmModel realm, Mode mode) { RealmModel realm, Mode mode) {
super(user); super(user);
@ -387,6 +370,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
if (role.getContainer().equals(roleContainer)) { if (role.getContainer().equals(roleContainer)) {
// We need to create new role mappings in LDAP // We need to create new role mappings in LDAP
cachedLDAPRoleMappings = null;
addRoleMappingInLDAP(mapperModel, role.getName(), ldapProvider, ldapUser); addRoleMappingInLDAP(mapperModel, role.getName(), ldapProvider, ldapUser);
} else { } else {
super.grantRole(role); super.grantRole(role);
@ -417,6 +401,30 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
return modelRoleMappings; return modelRoleMappings;
} }
protected Set<RoleModel> getLDAPRoleMappingsConverted(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, RoleContainerModel roleContainer) {
if (cachedLDAPRoleMappings != null) {
return new HashSet<>(cachedLDAPRoleMappings);
}
List<LDAPObject> ldapRoles = getLDAPRoleMappings(mapperModel, ldapProvider, ldapUser);
Set<RoleModel> roles = new HashSet<RoleModel>();
String roleNameLdapAttr = getRoleNameLdapAttribute(mapperModel);
for (LDAPObject role : ldapRoles) {
String roleName = role.getAttributeAsString(roleNameLdapAttr);
RoleModel modelRole = roleContainer.getRole(roleName);
if (modelRole == null) {
// Add role to local DB
modelRole = roleContainer.addRole(roleName);
}
roles.add(modelRole);
}
cachedLDAPRoleMappings = new HashSet<>(roles);
return roles;
}
@Override @Override
public void deleteRoleMapping(RoleModel role) { public void deleteRoleMapping(RoleModel role) {
RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm); RoleContainerModel roleContainer = getTargetRoleContainer(mapperModel, realm);
@ -440,6 +448,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
throw new ModelException("Not possible to delete LDAP role mappings as mapper mode is READ_ONLY"); throw new ModelException("Not possible to delete LDAP role mappings as mapper mode is READ_ONLY");
} else { } else {
// Delete ldap role mappings // Delete ldap role mappings
cachedLDAPRoleMappings = null;
deleteRoleMappingInLDAP(mapperModel, ldapProvider, ldapUser, ldapRole); deleteRoleMappingInLDAP(mapperModel, ldapProvider, ldapUser, ldapRole);
} }
} }

View file

@ -1,25 +1,33 @@
package org.keycloak.federation.ldap.mappers; package org.keycloak.federation.ldap.mappers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.mappers.MapperConfigValidationException; import org.keycloak.mappers.MapperConfigValidationException;
import org.keycloak.mappers.UserFederationMapper; import org.keycloak.mappers.UserFederationMapper;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderFactory;
import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.provider.ProviderConfigProperty; import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderEvent;
import org.keycloak.provider.ProviderEventListener;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory { public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMapperFactory {
private static final Logger logger = Logger.getLogger(RoleLDAPFederationMapperFactory.class);
public static final String PROVIDER_ID = "role-ldap-mapper"; public static final String PROVIDER_ID = "role-ldap-mapper";
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>(); protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
@ -40,8 +48,8 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
configProperties.add(membershipLDAPAttribute); configProperties.add(membershipLDAPAttribute);
ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes", ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes",
"Object classes of the role object divided by comma (if more values needed). In typical LDAP deployment it could be 'groupOfNames' or 'groupOfEntries' ", "Object class (or classes) of the role object. It's divided by comma if more classes needed. In typical LDAP deployment it could be 'groupOfNames' . In Active Directory it's usually 'group' ",
ProviderConfigProperty.STRING_TYPE, LDAPConstants.GROUP_OF_NAMES); ProviderConfigProperty.STRING_TYPE, null);
configProperties.add(roleObjectClasses); configProperties.add(roleObjectClasses);
List<String> modes = new LinkedList<String>(); List<String> modes = new LinkedList<String>();
@ -90,9 +98,46 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
return PROVIDER_ID; return PROVIDER_ID;
} }
// Sync roles from LDAP to Keycloak DB during creation or update of mapperModel
@Override
public void postInit(KeycloakSessionFactory factory) {
factory.register(new ProviderEventListener() {
@Override
public void onEvent(ProviderEvent event) {
if (event instanceof RealmModel.UserFederationMapperEvent) {
RealmModel.UserFederationMapperEvent mapperEvent = (RealmModel.UserFederationMapperEvent)event;
UserFederationMapperModel mapperModel = mapperEvent.getFederationMapper();
RealmModel realm = mapperEvent.getRealm();
KeycloakSession session = mapperEvent.getSession();
if (mapperModel.getFederationMapperType().equals(PROVIDER_ID)) {
try {
String federationProviderId = mapperModel.getFederationProviderId();
UserFederationProviderModel providerModel = KeycloakModelUtils.findUserFederationProviderById(federationProviderId, realm);
if (providerModel == null) {
throw new IllegalStateException("Can't find federation provider with ID [" + federationProviderId + "] in realm " + realm.getName());
}
UserFederationProviderFactory ldapFactory = (UserFederationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, providerModel.getProviderName());
LDAPFederationProvider ldapProvider = (LDAPFederationProvider) ldapFactory.getInstance(session, providerModel);
// Sync roles
new RoleLDAPFederationMapper().syncRolesFromLDAP(mapperModel, ldapProvider, realm);
} catch (Exception e) {
logger.warn("Exception during initial sync of roles from LDAP.", e);
}
}
}
}
});
}
@Override @Override
public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException { public void validateConfig(UserFederationMapperModel mapperModel) throws MapperConfigValidationException {
checkMandatoryConfigAttribute(RoleLDAPFederationMapper.ROLES_DN, "LDAP Roles DN", mapperModel); checkMandatoryConfigAttribute(RoleLDAPFederationMapper.ROLES_DN, "LDAP Roles DN", mapperModel);
checkMandatoryConfigAttribute(RoleLDAPFederationMapper.MODE, "Mode", mapperModel);
String realmMappings = mapperModel.getConfig().get(RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING); String realmMappings = mapperModel.getConfig().get(RoleLDAPFederationMapper.USE_REALM_ROLES_MAPPING);
boolean useRealmMappings = Boolean.parseBoolean(realmMappings); boolean useRealmMappings = Boolean.parseBoolean(realmMappings);

View file

@ -1,18 +1,13 @@
package org.keycloak.federation.ldap.mappers; package org.keycloak.federation.ldap.mappers;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProvider;
import org.keycloak.federation.ldap.LDAPUtils;
import org.keycloak.federation.ldap.idm.model.LDAPObject; import org.keycloak.federation.ldap.idm.model.LDAPObject;
import org.keycloak.federation.ldap.idm.query.Condition; import org.keycloak.federation.ldap.idm.query.Condition;
import org.keycloak.federation.ldap.idm.query.QueryParameter; import org.keycloak.federation.ldap.idm.query.QueryParameter;
import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery; import org.keycloak.federation.ldap.idm.query.internal.LDAPIdentityQuery;
import org.keycloak.mappers.UserFederationMapper;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProvider;
@ -20,7 +15,6 @@ import org.keycloak.models.UserModel;
import org.keycloak.models.utils.reflection.Property; import org.keycloak.models.utils.reflection.Property;
import org.keycloak.models.utils.reflection.PropertyCriteria; import org.keycloak.models.utils.reflection.PropertyCriteria;
import org.keycloak.models.utils.reflection.PropertyQueries; import org.keycloak.models.utils.reflection.PropertyQueries;
import org.keycloak.provider.ProviderConfigProperty;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -55,7 +49,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
String ldapAttrName = mapperModel.getConfig().get(LDAP_ATTRIBUTE); String ldapAttrName = mapperModel.getConfig().get(LDAP_ATTRIBUTE);
Object ldapAttrValue = ldapUser.getAttribute(ldapAttrName); Object ldapAttrValue = ldapUser.getAttribute(ldapAttrName);
if (ldapAttrValue != null) { if (ldapAttrValue != null && !ldapAttrValue.toString().trim().isEmpty()) {
Property<Object> userModelProperty = userModelProperties.get(userModelAttrName); Property<Object> userModelProperty = userModelProperties.get(userModelAttrName);
if (userModelProperty != null) { if (userModelProperty != null) {
@ -124,7 +118,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
} }
protected void setLDAPAttribute(String modelAttrName, String value) { protected void setLDAPAttribute(String modelAttrName, String value) {
if (modelAttrName.equals(userModelAttrName)) { if (modelAttrName.equalsIgnoreCase(userModelAttrName)) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.tracef("Pushing user attribute to LDAP. Model attribute name: %s, LDAP attribute name: %s, Attribute value: %s", modelAttrName, ldapAttrName, value); logger.tracef("Pushing user attribute to LDAP. Model attribute name: %s, LDAP attribute name: %s, Attribute value: %s", modelAttrName, ldapAttrName, value);
} }
@ -157,7 +151,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
// Change conditions and use ldapAttribute instead of userModel // Change conditions and use ldapAttribute instead of userModel
for (Condition condition : query.getConditions()) { for (Condition condition : query.getConditions()) {
QueryParameter param = condition.getParameter(); QueryParameter param = condition.getParameter();
if (param != null && param.getName().equals(userModelAttrName)) { if (param != null && param.getName().equalsIgnoreCase(userModelAttrName)) {
param.setName(ldapAttrName); param.setName(ldapAttrName);
} }
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class AccountSpi implements Spi { public class AccountSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -38,7 +38,7 @@ public class AccountBean {
} }
public String getUsername() { public String getUsername() {
return user.getUsername(); return profileFormData != null ? profileFormData.getFirst("username") : user.getUsername();
} }
public String getEmail() { public String getEmail() {

View file

@ -46,4 +46,8 @@ public class RealmBean {
return realm.getSupportedLocales(); return realm.getSupportedLocales();
} }
public boolean isEditUsernameAllowed() {
return realm.isEditUsernameAllowed();
}
} }

View file

@ -10,7 +10,7 @@ import org.keycloak.provider.Spi;
public class ThemeSpi implements Spi { public class ThemeSpi implements Spi {
@Override @Override
public boolean isPrivate() { public boolean isInternal() {
return true; return true;
} }

View file

@ -16,11 +16,11 @@
<div class="form-group ${messagesPerField.printIfExists('username','has-error')}"> <div class="form-group ${messagesPerField.printIfExists('username','has-error')}">
<div class="col-sm-2 col-md-2"> <div class="col-sm-2 col-md-2">
<label for="username" class="control-label">${msg("username")}</label> <label for="username" class="control-label">${msg("username")}</label> <#if realm.editUsernameAllowed><span class="required">*</span></#if>
</div> </div>
<div class="col-sm-10 col-md-10"> <div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="username" name="username" disabled="disabled" value="${(account.username!'')?html}"/> <input type="text" class="form-control" id="username" name="username" <#if !realm.editUsernameAllowed>disabled="disabled"</#if> value="${(account.username!'')?html}"/>
</div> </div>
</div> </div>

View file

@ -80,7 +80,7 @@ totpStep1=Installieren Sie <a href="https://fedorahosted.org/freeotp/" target="_
totpStep2=\u00D6ffnen Sie die Applikation und scannen Sie den Barcode oder geben sie den Code ein. totpStep2=\u00D6ffnen Sie die Applikation und scannen Sie den Barcode oder geben sie den Code ein.
totpStep3=Geben Sie den One-time Code welcher die Applikation generiert hat ein und klicken Sie auf Speichern. totpStep3=Geben Sie den One-time Code welcher die Applikation generiert hat ein und klicken Sie auf Speichern.
missingUsernameMessage=Bitte geben Sie einen Benutzernamen ein.
missingFirstNameMessage=Bitte geben Sie einen Vornamen ein. missingFirstNameMessage=Bitte geben Sie einen Vornamen ein.
missingEmailMessage=Bitte geben Sie eine E-Mail Adresse ein. missingEmailMessage=Bitte geben Sie eine E-Mail Adresse ein.
missingLastNameMessage=Bitte geben Sie einen Nachnamen ein. missingLastNameMessage=Bitte geben Sie einen Nachnamen ein.

View file

@ -96,6 +96,7 @@ totpStep1=Install <a href="https://fedorahosted.org/freeotp/" target="_blank">Fr
totpStep2=Open the application and scan the barcode or enter the key. totpStep2=Open the application and scan the barcode or enter the key.
totpStep3=Enter the one-time code provided by the application and click Save to finish the setup. totpStep3=Enter the one-time code provided by the application and click Save to finish the setup.
missingUsernameMessage=Please specify username.
missingFirstNameMessage=Please specify first name. missingFirstNameMessage=Please specify first name.
invalidEmailMessage=Invalid email address. invalidEmailMessage=Invalid email address.
missingLastNameMessage=Please specify last name. missingLastNameMessage=Please specify last name.

View file

@ -597,7 +597,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
if (instance && instance.alias) { if (instance && instance.alias) {
} else { } else {
$scope.identityProvider.updateProfileFirstLogin = false; $scope.identityProvider.updateProfileFirstLoginMode = "on";
} }
}; };
@ -645,7 +645,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
} else { } else {
$scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format; $scope.identityProvider.config.nameIDPolicyFormat = $scope.nameIdFormats[0].format;
$scope.identityProvider.updateProfileFirstLogin = false; $scope.identityProvider.updateProfileFirstLoginMode = "off";
} }
} }
@ -663,7 +663,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
$scope.identityProvider.alias = providerFactory.id; $scope.identityProvider.alias = providerFactory.id;
$scope.identityProvider.providerId = providerFactory.id; $scope.identityProvider.providerId = providerFactory.id;
$scope.identityProvider.enabled = true; $scope.identityProvider.enabled = true;
$scope.identityProvider.updateProfileFirstLogin = false; $scope.identityProvider.updateProfileFirstLoginMode = "off";
$scope.identityProvider.authenticateByDefault = false; $scope.identityProvider.authenticateByDefault = false;
$scope.newIdentityProvider = true; $scope.newIdentityProvider = true;
} }

View file

@ -198,6 +198,7 @@ module.controller('UserListCtrl', function($scope, realm, User) {
module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) { module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) {
$scope.realm = realm; $scope.realm = realm;
$scope.create = !user.id; $scope.create = !user.id;
$scope.editUsername = $scope.create || $scope.realm.editUsernameAllowed;
if ($scope.create) { if ($scope.create) {
$scope.user = { enabled: true, attributes: {} } $scope.user = { enabled: true, attributes: {} }

View file

@ -559,7 +559,7 @@ function roleControl($scope, realm, role, roles, clients,
$scope.realmMappings.push(role); $scope.realmMappings.push(role);
} }
} }
$scope.selectRealmRoles = []; $scope.selectedRealmRoles = [];
}); });
}; };

View file

@ -17,7 +17,7 @@
<select id="available" class="form-control" multiple size="5" <select id="available" class="form-control" multiple size="5"
ng-multiple="true" ng-multiple="true"
ng-model="selectedRealmRoles" ng-model="selectedRealmRoles"
ng-options="r for r in availableRealmRoles"> ng-options="r for r in availableRealmRoles | orderBy:'toString()'">
</select> </select>
<button class="btn btn-default" type="submit" ng-click="addRealmDefaultRole()" tooltip="Assign role" tooltip-placement="right"> <button class="btn btn-default" type="submit" ng-click="addRealmDefaultRole()" tooltip="Assign role" tooltip-placement="right">
Add selected <i class="fa fa-angle-double-right"></i> Add selected <i class="fa fa-angle-double-right"></i>
@ -29,7 +29,7 @@
<select id="assigned" class="form-control" multiple size=5 <select id="assigned" class="form-control" multiple size=5
ng-multiple="true" ng-multiple="true"
ng-model="selectedRealmDefRoles" ng-model="selectedRealmDefRoles"
ng-options="r for r in realm.defaultRoles"> ng-options="r for r in realm.defaultRoles | orderBy:'toString()'">
</select> </select>
<button class="btn btn-default" type="submit" ng-click="deleteRealmDefaultRole()" tooltip="Unassign role" tooltip-placement="left"> <button class="btn btn-default" type="submit" ng-click="deleteRealmDefaultRole()" tooltip="Unassign role" tooltip-placement="left">
<i class="fa fa-angle-double-left"></i> Remove selected <i class="fa fa-angle-double-left"></i> Remove selected
@ -55,7 +55,7 @@
<select id="available-client" class="form-control" multiple size="5" <select id="available-client" class="form-control" multiple size="5"
ng-multiple="true" ng-multiple="true"
ng-model="selectedClientRoles" ng-model="selectedClientRoles"
ng-options="r for r in availableClientRoles"> ng-options="r for r in availableClientRoles | orderBy:'toString()'">
</select> </select>
<button class="btn btn-default" type="submit" ng-click="addClientDefaultRole()" tooltip="Assign role" tooltip-placement="right"> <button class="btn btn-default" type="submit" ng-click="addClientDefaultRole()" tooltip="Assign role" tooltip-placement="right">
Add selected <i class="fa fa-angle-double-right"></i> Add selected <i class="fa fa-angle-double-right"></i>
@ -67,7 +67,7 @@
<select id="assigned-client" class="form-control" multiple size=5 <select id="assigned-client" class="form-control" multiple size=5
ng-multiple="true" ng-multiple="true"
ng-model="selectedClientDefRoles" ng-model="selectedClientDefRoles"
ng-options="r for r in client.defaultRoles"> ng-options="r for r in client.defaultRoles | orderBy:'toString()'">
</select> </select>
<button class="btn btn-default" type="submit" ng-click="rmClientDefaultRole()" tooltip="Unassign role" tooltip-placement="left"> <button class="btn btn-default" type="submit" ng-click="rmClientDefaultRole()" tooltip="Unassign role" tooltip-placement="left">
<i class="fa fa-angle-double-left"></i> Remove selected <i class="fa fa-angle-double-left"></i> Remove selected

View file

@ -59,11 +59,24 @@
<kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip> <kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label> <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-6"> <div class="col-md-2">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch /> <div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
</div> </div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip> <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">GUI order</label> <label class="col-md-2 control-label" for="guiOrder">GUI order</label>

View file

@ -60,11 +60,24 @@
<kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip> <kc-tooltip>Enable/disable new users can read any stored tokens. This assigns the broker.read-token role.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label> <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-6"> <div class="col-md-2">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch /> <div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
</div> </div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip> <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="guiOrder">GUI order</label> <label class="col-md-2 control-label" for="guiOrder">GUI order</label>

View file

@ -70,11 +70,24 @@
<kc-tooltip>Enable/disable this identity provider.</kc-tooltip> <kc-tooltip>Enable/disable this identity provider.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label> <label class="col-md-2 control-label" for="updateProfileFirstLoginMode">Update Profile on First Login</label>
<div class="col-md-6"> <div class="col-md-2">
<input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch /> <div>
<select id="updateProfileFirstLoginMode" ng-model="identityProvider.updateProfileFirstLoginMode" class="form-control">
<option value="on">On</option>
<option value="missing">On missing info</option>
<option value="off">Off</option>
</select>
</div>
</div> </div>
<kc-tooltip>Indicates if user must update his profile right after the first login.</kc-tooltip> <kc-tooltip>Define under which conditions must user update his profile right after the first login.</kc-tooltip>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="trustEmail">Trust email</label>
<div class="col-md-6">
<input ng-model="identityProvider.trustEmail" name="identityProvider.trustEmail" id="trustEmail" onoffswitch />
</div>
<kc-tooltip>If enabled then email provided by this provider is not verified even if verification is enabled for the realm.</kc-tooltip>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-md-2 control-label" for="authenticateByDefault">Authenticate By Default</label> <label class="col-md-2 control-label" for="authenticateByDefault">Authenticate By Default</label>

View file

@ -8,7 +8,7 @@
<caption class="hidden">Table of identity providers</caption> <caption class="hidden">Table of identity providers</caption>
<thead> <thead>
<tr> <tr>
<th colspan="3" class="kc-table-actions"> <th colspan="4" class="kc-table-actions">
<div class="dropdown pull-right"> <div class="dropdown pull-right">
<select class="form-control" ng-model="provider" <select class="form-control" ng-model="provider"
ng-options="p.name group by p.groupName for p in allProviders track by p.id" ng-options="p.name group by p.groupName for p in allProviders track by p.id"
@ -21,6 +21,7 @@
<tr ng-show="configuredProviders.length > 0"> <tr ng-show="configuredProviders.length > 0">
<th>Name</th> <th>Name</th>
<th>Provider</th> <th>Provider</th>
<th>Enabled</th>
<th width="15%">GUI order</th> <th width="15%">GUI order</th>
</tr> </tr>
</thead> </thead>
@ -30,6 +31,7 @@
<a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a> <a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.alias}}">{{identityProvider.alias}}</a>
</td> </td>
<td>{{identityProvider.providerId}}</td> <td>{{identityProvider.providerId}}</td>
<td>{{identityProvider.enabled}}</td>
<td>{{identityProvider.config.guiOrder}}</td> <td>{{identityProvider.config.guiOrder}}</td>
</tr> </tr>
</tbody> </tbody>

View file

@ -19,6 +19,13 @@
</div> </div>
<kc-tooltip>If enabled then username field is hidden from registration form and email is used as username for new user.</kc-tooltip> <kc-tooltip>If enabled then username field is hidden from registration form and email is used as username for new user.</kc-tooltip>
</div> </div>
<div class="form-group">
<label for="editUsernameAllowed" class="col-md-2 control-label">Edit username</label>
<div class="col-md-6">
<input ng-model="realm.editUsernameAllowed" name="editUsernameAllowed" id="editUsernameAllowed" onoffswitch />
</div>
<kc-tooltip>If enabled, the username field is editable, readonly otherwise.</kc-tooltip>
</div>
<div class="form-group"> <div class="form-group">
<label for="resetPasswordAllowed" class="col-md-2 control-label">Forget password</label> <label for="resetPasswordAllowed" class="col-md-2 control-label">Forget password</label>
<div class="col-md-6"> <div class="col-md-6">
@ -40,13 +47,6 @@
</div> </div>
<kc-tooltip>Require the user to verify their email address the first time they login.</kc-tooltip> <kc-tooltip>Require the user to verify their email address the first time they login.</kc-tooltip>
</div> </div>
<div class="form-group">
<label for="passwordCredentialGrantAllowed" class="col-md-2 control-label">Direct Grant API</label>
<div class="col-md-6">
<input ng-model="realm.passwordCredentialGrantAllowed" name="passwordCredentialGrantAllowed" id="passwordCredentialGrantAllowed" onoffswitch />
</div>
<kc-tooltip>Enable/disable REST API for login/token grant access</kc-tooltip>
</div>
<div class="form-group"> <div class="form-group">
<label for="sslRequired" class="col-md-2 control-label">Require SSL</label> <label for="sslRequired" class="col-md-2 control-label">Require SSL</label>
<div class="col-md-2"> <div class="col-md-2">

Some files were not shown because too many files have changed in this diff Show more