Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2017-02-09 09:13:00 -05:00
commit d9633dc20c
36 changed files with 1122 additions and 507 deletions

View file

@ -87,6 +87,10 @@
}
kc.flow = initOptions.flow;
}
if (initOptions.timeSkew != null) {
kc.timeSkew = initOptions.timeSkew;
}
}
if (!kc.responseMode) {
@ -162,12 +166,8 @@
kc.onAuthSuccess && kc.onAuthSuccess();
initPromise.setSuccess();
}).error(function () {
kc.onAuthError && kc.onAuthError();
if (initOptions.onLoad) {
onLoad();
} else {
initPromise.setError();
}
setToken(null, null, null);
initPromise.setSuccess();
});
});
} else {
@ -369,6 +369,11 @@
throw 'Not authenticated';
}
if (kc.timeSkew == null) {
console.info('[KEYCLOAK] Unable to determine if token is expired as timeskew is not set');
return true;
}
var expiresIn = kc.tokenParsed['exp'] - Math.ceil(new Date().getTime() / 1000) + kc.timeSkew;
if (minValidity) {
expiresIn -= minValidity;
@ -653,12 +658,7 @@
if (token) {
kc.token = token;
kc.tokenParsed = decodeToken(token);
var sessionId = kc.realm + '/' + kc.tokenParsed.sub;
if (kc.tokenParsed.session_state) {
sessionId = sessionId + '/' + kc.tokenParsed.session_state;
}
kc.sessionId = sessionId;
kc.sessionId = kc.tokenParsed.session_state;
kc.authenticated = true;
kc.subject = kc.tokenParsed.sub;
kc.realmAccess = kc.tokenParsed.realm_access;
@ -666,6 +666,9 @@
if (timeLocal) {
kc.timeSkew = Math.floor(timeLocal / 1000) - kc.tokenParsed.iat;
}
if (kc.timeSkew != null) {
console.info('[KEYCLOAK] Estimated time difference between browser and server is ' + kc.timeSkew + ' seconds');
if (kc.onTokenExpired) {
@ -677,11 +680,7 @@
kc.tokenTimeoutHandle = setTimeout(kc.onTokenExpired, expiresIn);
}
}
} else {
kc.updateToken(-1);
}
} else if (refreshToken) {
kc.updateToken(-1);
} else {
delete kc.token;
delete kc.tokenParsed;

View file

@ -53,7 +53,8 @@
req.send();
} else {
if (clientId === init.clientId && origin === init.origin) {
if (sessionState === cookie) {
var c = cookie.split('/');
if (sessionState === c[2]) {
callback('unchanged');
} else {
callback('changed');
@ -81,7 +82,7 @@
var origin = event.origin;
var data = event.data.split(' ');
if (data.length != 2) {
event.source.postMessage('error', origin);
return;
}
var clientId = data[0];

View file

@ -0,0 +1,33 @@
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly>
<id>server-dist</id>
<formats>
<format>dir</format>
</formats>
<fileSets>
<fileSet>
<directory>${localRepository}/org/keycloak</directory>
<includes>
<include>**/*.zip</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -25,16 +25,25 @@
</parent>
<artifactId>keycloak-dist-downloads</artifactId>
<packaging>pom</packaging>
<packaging>jar</packaging>
<name>Keycloak Release Downloads</name>
<description/>
<dependencies>
</dependencies>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
@ -43,342 +52,22 @@
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>server-downloads</id>
<phase>install</phase>
<phase>package</phase>
<goals>
<goal>copy</goal>
<goal>java</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-dist</artifactId>
<type>zip</type>
<destFileName>keycloak-${project.version}.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-dist</artifactId>
<type>tar.gz</type>
<destFileName>keycloak-${project.version}.tar.gz</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-demo-dist</artifactId>
<type>zip</type>
<destFileName>keycloak-demo-${project.version}.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-demo-dist</artifactId>
<type>tar.gz</type>
<destFileName>keycloak-demo-${project.version}.tar.gz</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-overlay</artifactId>
<type>zip</type>
<destFileName>keycloak-overlay-${project.version}.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-overlay</artifactId>
<type>tar.gz</type>
<destFileName>keycloak-overlay-${project.version}.tar.gz</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-proxy-dist</artifactId>
<type>zip</type>
<destFileName>keycloak-proxy-${project.version}.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-api-docs-dist</artifactId>
<type>zip</type>
<destFileName>keycloak-api-docs-${project.version}.zip</destFileName>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-examples-dist</artifactId>
<type>zip</type>
<destFileName>keycloak-examples-${project.version}.zip</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>target/${project.version}</outputDirectory>
</configuration>
</execution>
<execution>
<id>adapter-downloads</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-eap6-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-eap6-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty81-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty81-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty91-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty91-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty92-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty92-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty93-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-jetty93-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-js-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-js-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat6-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat6-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat7-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat7-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wf8-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wf8-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-fuse-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-fuse-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
</artifactItems>
<outputDirectory>target/${project.version}/adapters/keycloak-oidc</outputDirectory>
</configuration>
</execution>
<execution>
<id>saml-adapter-downloads</id>
<phase>install</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-as7-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-as7-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap6-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-eap6-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty81-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty81-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty92-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty92-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty93-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-jetty93-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat6-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat6-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat7-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat7-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat8-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-tomcat8-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>zip</type>
</artifactItem>
<artifactItem>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-saml-wildfly-adapter-dist</artifactId>
<type>tar.gz</type>
</artifactItem>
</artifactItems>
<outputDirectory>target/${project.version}/adapters/saml</outputDirectory>
<mainClass>CopyDependencies</mainClass>
<arguments>
<argument>${settings.localRepository}</argument>
<argument>${project.build.directory}</argument>
<argument>${project.version}</argument>
</arguments>
</configuration>
</execution>
</executions>

View file

@ -0,0 +1,49 @@
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
/**
* Created by st on 06.02.17.
*/
public class CopyDependencies {
public static void main(String[] args) throws IOException {
String version = args[2];
Path repository = new File(args[0]).toPath().resolve("org").resolve("keycloak");
Path targetRoot = new File(args[1]).toPath().resolve(version);
BufferedReader br = new BufferedReader(new InputStreamReader(CopyDependencies.class.getResourceAsStream("files")));
Path target = targetRoot;
for (String l = br.readLine(); l != null; l = br.readLine()) {
if (l.startsWith("./")) {
target = targetRoot.resolve(l.replace("./", "").replace('/', File.separatorChar));
if (!target.toFile().isDirectory()) {
target.toFile().mkdirs();
}
} else if (l.trim().length() > 0) {
String[] t = l.trim().split(":");
String artifactName = t[0];
String destName = t.length == 1 ? artifactName : t[1];
File artifactDir = repository.resolve(artifactName).resolve(version).toFile();
for (File f : artifactDir.listFiles((file, name) -> name.contains(".tar.gz") || name.contains(".zip"))) {
Files.copy(f.toPath(), target.resolve(f.getName().replace(artifactName, destName)), StandardCopyOption.REPLACE_EXISTING);
}
System.out.println(artifactName);
}
}
br.close();
}
}

View file

@ -0,0 +1,33 @@
./
keycloak-server-dist:keycloak
keycloak-demo-dist:keycloak-demo
keycloak-server-overlay:keycloak-overlay
keycloak-proxy-dist:keycloak-proxy
keycloak-api-docs-dist:keycloak-api-docs
keycloak-examples-dist:keycloak-examples
./adapters/keycloak-oidc
keycloak-as7-adapter-dist
keycloak-eap6-adapter-dist
keycloak-jetty81-adapter-dist
keycloak-jetty91-adapter-dist
keycloak-jetty92-adapter-dist
keycloak-jetty93-adapter-dist
keycloak-js-adapter-dist
keycloak-tomcat6-adapter-dist
keycloak-tomcat7-adapter-dist
keycloak-tomcat8-adapter-dist
keycloak-wf8-adapter-dist
keycloak-wildfly-adapter-dist
keycloak-fuse-adapter-dist
./adapters/saml
keycloak-saml-as7-adapter-dist
keycloak-saml-eap6-adapter-dist
keycloak-saml-jetty81-adapter-dist
keycloak-saml-jetty92-adapter-dist
keycloak-saml-jetty93-adapter-dist
keycloak-saml-tomcat6-adapter-dist
keycloak-saml-tomcat7-adapter-dist
keycloak-saml-tomcat8-adapter-dist
keycloak-saml-wildfly-adapter-dist

View file

@ -55,6 +55,13 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-undertow-adapter</artifactId>
</dependency>
<!-- Authorization -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-feature-pack</artifactId>

View file

@ -34,6 +34,7 @@
<module name="org.keycloak.keycloak-adapter-spi"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-authz-client"/>
</dependencies>
</module>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ * Copyright 2016 Red Hat, Inc. and/or its affiliates
~ * and other contributors as indicated by the @author tags.
~ *
~ * Licensed under the Apache License, Version 2.0 (the "License");
~ * you may not use this file except in compliance with the License.
~ * You may obtain a copy of the License at
~ *
~ * http://www.apache.org/licenses/LICENSE-2.0
~ *
~ * Unless required by applicable law or agreed to in writing, software
~ * distributed under the License is distributed on an "AS IS" BASIS,
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ * See the License for the specific language governing permissions and
~ * limitations under the License.
-->
<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-client">
<resources>
<artifact name="${org.keycloak:keycloak-authz-client}"/>
</resources>
<dependencies>
<module name="org.bouncycastle" />
<module name="javax.api"/>
<module name="javax.activation.api"/>
<module name="sun.jdk" optional="true" />
<module name="javax.ws.rs.api"/>
<module name="org.keycloak.keycloak-core"/>
<module name="org.keycloak.keycloak-common"/>
<module name="org.apache.httpcomponents"/>
<module name="com.fasterxml.jackson.core.jackson-core"/>
<module name="com.fasterxml.jackson.core.jackson-annotations"/>
<module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
</dependencies>
</module>

View file

@ -1,9 +1,5 @@
embed-host-controller --domain-config=domain.xml
# Early versions of keycloak used "default" for the standalone profile name.
# Yours maybe be something completely different.
set standaloneProfile=auth-server-standalone
# Early versions of keycloak used "ha" for the clustered profile name.
# Yours maybe be something completely different.
set clusteredProfile=auth-server-clustered
@ -12,125 +8,6 @@ set clusteredProfile=auth-server-clustered
set pathToJson=../domain/configuration/keycloak-server.json
echo *** Begin Migration of /profile=$standaloneProfile ***
echo
# Migrate from 1.8.1 to 1.9.1
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=work/:read-resource
echo Adding local-cache=work to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=work/:add(indexing=NONE,start=LAZY)
echo
end-if
# realmVersions cache deprecated in 2.1.0
#if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:read-resource
# echo Adding local-cache=realmVersions to keycloak cache container...
# /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:add(indexing=NONE,start=LAZY)
# /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/component=transaction/:write-attribute(name=mode,value=BATCH)
# echo
#end-if
# Migrate from 1.9.1 to 1.9.2
if (result == NONE) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:read-attribute(name=strategy)
echo Adding eviction strategy to keycloak users cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=max-entries,value=10000)
echo
end-if
# Migrate from 1.9.2 to 1.9.8
# NO CHANGES
# Migrate from 1.9.8 to 2.0.0
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/:read-resource
echo Adding local-cache=authorization to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/:add(indexing=NONE,start=LAZY)
echo
end-if
if (result == undefined) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:read-attribute(name=strategy,include-defaults=false)
echo Updating authorization cache container..
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=max-entries,value=100)
end-if
# Migrate from 2.0.0 to 2.1.0
if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:read-resource
echo Removing deprecated cache 'realmVersions'
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:remove
echo
end-if
# Migrate kecloak-server.json (deprecated in 2.2.0)
if (result == []) of /profile=$standaloneProfile/subsystem=keycloak-server/:read-children-names(child-type=spi)
echo Migrating keycloak-server.json to keycloak-server subsystem...
/profile=$standaloneProfile/subsystem=keycloak-server/:migrate-json(file=$pathToJson)
echo
end-if
# Find if we are using jpa or mongo
if (result == mongo) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=realm/:read-attribute(name=default-provider)
set persistenceProvider=mongo
else
set persistenceProvider=jpa
end-if
# Migrate from 2.1.0 to 2.2.0
if (result == update) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-get(name=properties,key=databaseSchema)
echo Updating connectionsJpa default properties...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-remove(name=properties,key=databaseSchema)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=initializeEmpty,value=true)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=migrationStrategy,value=update)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=migrationExport,value=${jboss.home.dir}/keycloak-database-update.sql)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=userFederatedStorage/:read-resource
echo Adding spi=userFederatedStorage...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=userFederatedStorage/:add(default-provider=$persistenceProvider)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/:read-resource
echo Adding spi=jta-lookup...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/:add(default-provider=${keycloak.jta.lookup.provider:jboss})
/profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/provider=jboss/:add(enabled=true)
echo
end-if
# Migrate from 2.2.0 to 2.2.1
# NO CHANGES
# Migrate from 2.2.1 to 2.3.0
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/:read-resource
echo Adding local-cache=keys to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/:add(indexing=NONE,start=LAZY)
echo
end-if
if (result == undefined) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:read-attribute(name=strategy,include-defaults=false)
echo Updating eviction and expiration in local-cache=keys...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:write-attribute(name=max-entries,value=1000)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=expiration/:write-attribute(name=max-idle,value=3600000)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/:read-resource
echo Adding spi=publicKeyStorage...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/:add
/profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/provider=infinispan/:add(properties={minTimeBetweenRequests => "10"},enabled=true)
echo
end-if
# Migrate from 2.3.0 to 2.4.0
# NO CHANGES
# Migrate from 2.4.0 to 2.5.0
if (result == NONE) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:read-attribute(name=strategy)
echo Adding eviction strategy to keycloak realms cache...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:write-attribute(name=max-entries,value=10000)
echo
end-if
echo *** End Migration of /profile=$standaloneProfile ***
echo
echo
echo *** Begin Migration of /profile=$clusteredProfile ***
echo
@ -260,4 +137,4 @@ if (result == NONE) of /profile=$clusteredProfile/subsystem=infinispan/cache-con
echo
end-if
echo *** End Migration ***
echo *** End Migration of /profile=$clusteredProfile ***

View file

@ -0,0 +1,128 @@
embed-host-controller --domain-config=domain.xml
# Early versions of keycloak used "default" for the standalone profile name.
# Yours maybe be something completely different.
set standaloneProfile=auth-server-standalone
# keycloak-server.json is not normally on this path.
set pathToJson=../domain/configuration/keycloak-server.json
echo *** Begin Migration of /profile=$standaloneProfile ***
echo
# Migrate from 1.8.1 to 1.9.1
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=work/:read-resource
echo Adding local-cache=work to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=work/:add(indexing=NONE,start=LAZY)
echo
end-if
# realmVersions cache deprecated in 2.1.0
#if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:read-resource
# echo Adding local-cache=realmVersions to keycloak cache container...
# /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:add(indexing=NONE,start=LAZY)
# /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/component=transaction/:write-attribute(name=mode,value=BATCH)
# echo
#end-if
# Migrate from 1.9.1 to 1.9.2
if (result == NONE) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:read-attribute(name=strategy)
echo Adding eviction strategy to keycloak users cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=users/component=eviction/:write-attribute(name=max-entries,value=10000)
echo
end-if
# Migrate from 1.9.2 to 1.9.8
# NO CHANGES
# Migrate from 1.9.8 to 2.0.0
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/:read-resource
echo Adding local-cache=authorization to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/:add(indexing=NONE,start=LAZY)
echo
end-if
if (result == undefined) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:read-attribute(name=strategy,include-defaults=false)
echo Updating authorization cache container..
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/component=eviction/:write-attribute(name=max-entries,value=100)
end-if
# Migrate from 2.0.0 to 2.1.0
if (outcome == success) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:read-resource
echo Removing deprecated cache 'realmVersions'
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/:remove
echo
end-if
# Migrate kecloak-server.json (deprecated in 2.2.0)
if (result == []) of /profile=$standaloneProfile/subsystem=keycloak-server/:read-children-names(child-type=spi)
echo Migrating keycloak-server.json to keycloak-server subsystem...
/profile=$standaloneProfile/subsystem=keycloak-server/:migrate-json(file=$pathToJson)
echo
end-if
# Find if we are using jpa or mongo
if (result == mongo) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=realm/:read-attribute(name=default-provider)
set persistenceProvider=mongo
else
set persistenceProvider=jpa
end-if
# Migrate from 2.1.0 to 2.2.0
if (result == update) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-get(name=properties,key=databaseSchema)
echo Updating connectionsJpa default properties...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-remove(name=properties,key=databaseSchema)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=initializeEmpty,value=true)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=migrationStrategy,value=update)
/profile=$standaloneProfile/subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=migrationExport,value=${jboss.home.dir}/keycloak-database-update.sql)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=userFederatedStorage/:read-resource
echo Adding spi=userFederatedStorage...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=userFederatedStorage/:add(default-provider=$persistenceProvider)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/:read-resource
echo Adding spi=jta-lookup...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/:add(default-provider=${keycloak.jta.lookup.provider:jboss})
/profile=$standaloneProfile/subsystem=keycloak-server/spi=jta-lookup/provider=jboss/:add(enabled=true)
echo
end-if
# Migrate from 2.2.0 to 2.2.1
# NO CHANGES
# Migrate from 2.2.1 to 2.3.0
if (outcome == failed) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/:read-resource
echo Adding local-cache=keys to keycloak cache container...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/:add(indexing=NONE,start=LAZY)
echo
end-if
if (result == undefined) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:read-attribute(name=strategy,include-defaults=false)
echo Updating eviction and expiration in local-cache=keys...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=eviction/:write-attribute(name=max-entries,value=1000)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=keys/component=expiration/:write-attribute(name=max-idle,value=3600000)
echo
end-if
if (outcome == failed) of /profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/:read-resource
echo Adding spi=publicKeyStorage...
/profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/:add
/profile=$standaloneProfile/subsystem=keycloak-server/spi=publicKeyStorage/provider=infinispan/:add(properties={minTimeBetweenRequests => "10"},enabled=true)
echo
end-if
# Migrate from 2.3.0 to 2.4.0
# NO CHANGES
# Migrate from 2.4.0 to 2.5.0
if (result == NONE) of /profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:read-attribute(name=strategy)
echo Adding eviction strategy to keycloak realms cache...
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:write-attribute(name=strategy,value=LRU)
/profile=$standaloneProfile/subsystem=infinispan/cache-container=keycloak/local-cache=realms/component=eviction/:write-attribute(name=max-entries,value=10000)
echo
end-if
echo *** End Migration of /profile=$standaloneProfile ***

View file

@ -124,6 +124,11 @@ public class LDAPIdentityStore implements IdentityStore {
String rdnAttrVal = ldapObject.getAttributeAsString(rdnAttrName);
// Could be the case when RDN attribute of the target object is not included in Keycloak mappers
if (rdnAttrVal == null) {
return;
}
String oldRdnAttrVal = ldapObject.getDn().getFirstRdnAttrValue();
if (!oldRdnAttrVal.equals(rdnAttrVal)) {
LDAPDn newLdapDn = ldapObject.getDn().getParentDn();

View file

@ -40,9 +40,11 @@ public class MigrateUserFedToComponent extends AbstractUserFedToComponent {
protected void generateStatementsImpl() throws CustomChangeException {
List<ProviderFactory> factories = kcSession.getKeycloakSessionFactory().getProviderFactories(UserStorageProvider.class);
for (ProviderFactory factory : factories) {
if (!factory.getId().equals(LDAPConstants.LDAP_PROVIDER)) {
convertFedProviderToComponent(factory.getId(), null);
}
}
}
@Override
protected String getTaskId() {

View file

@ -27,7 +27,6 @@ public class PortLdapUserFedToComponentModel extends AbstractUserFedToComponent
@Override
protected void generateStatementsImpl() throws CustomChangeException {
String providerId = LDAPConstants.LDAP_PROVIDER;
convertFedProviderToComponent(LDAPConstants.LDAP_PROVIDER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper");
}

View file

@ -35,6 +35,9 @@ public class KeyInfoTools {
* @return The object or {@code null} if not found.
*/
public static <T> T getContent(Iterable<Object> objects, Class<T> clazz) {
if (objects == null) {
return null;
}
for (Object o : objects) {
if (clazz.isInstance(o)) {
return (T) o;
@ -45,11 +48,11 @@ public class KeyInfoTools {
public static KeyName getKeyName(KeyInfo keyInfo) {
return getContent(keyInfo.getContent(), KeyName.class);
return keyInfo == null ? null : getContent(keyInfo.getContent(), KeyName.class);
}
public static X509Data getX509Data(KeyInfo keyInfo) {
return getContent(keyInfo.getContent(), X509Data.class);
return keyInfo == null ? null : getContent(keyInfo.getContent(), X509Data.class);
}
public static X509Certificate getX509Certificate(KeyInfo keyInfo) {

View file

@ -801,7 +801,7 @@ public class ModelToRepresentation {
representation.setType(model.getType());
representation.setDecisionStrategy(model.getDecisionStrategy());
representation.setLogic(model.getLogic());
representation.setConfig(model.getConfig());
representation.setConfig(new HashMap<>(model.getConfig()));
return representation;
}

View file

@ -173,13 +173,17 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper {
setIfNotEmpty(user::setLastName, attributeValuesInContext);
} else {
List<String> currentAttributeValues = user.getAttributes().get(attribute);
if (attributeValuesInContext != null
&& currentAttributeValues != null
&& !CollectionUtil.collectionEquals(attributeValuesInContext, currentAttributeValues)) {
user.setAttribute(attribute, attributeValuesInContext);
} else if (attributeValuesInContext == null) {
if (attributeValuesInContext == null) {
// attribute no longer sent by brokered idp, remove it
user.removeAttribute(attribute);
} else if (currentAttributeValues == null) {
// new attribute sent by brokered idp, add it
user.setAttribute(attribute, attributeValuesInContext);
} else if (!CollectionUtil.collectionEquals(attributeValuesInContext, currentAttributeValues)) {
// attribute sent by brokered idp has different values as before, update it
user.setAttribute(attribute, attributeValuesInContext);
}
// attribute allready set
}
}

View file

@ -371,7 +371,7 @@ public class ExportUtils {
Set<Resource> policyResources = policy.getResources();
if (!policyResources.isEmpty()) {
List<String> resourceNames = scopes.stream().map(Scope::getName).collect(Collectors.toList());
List<String> resourceNames = policyResources.stream().map(Resource::getName).collect(Collectors.toList());
config.put("resources", JsonSerialization.writeValueAsString(resourceNames));
}

View file

@ -740,7 +740,7 @@ public class AuthenticationManager {
if (!isSessionValid(realm, userSession)) {
// Check if accessToken was for the offline session.
if (!isCookie) {
UserSessionModel offlineUserSession = session.sessions().getUserSession(realm, token.getSessionState());
UserSessionModel offlineUserSession = session.sessions().getOfflineUserSession(realm, token.getSessionState());
if (isOfflineSessionValid(realm, offlineUserSession)) {
return new AuthResult(user, offlineUserSession, token);
}

View file

@ -0,0 +1,210 @@
How To Run various testsuite configurations
===========================================
## Base steps
It's recomended to build the workspace including distribution.
````
cd $KEYCLOAK_SOURCES
mvn clean install -DskipTests=true
cd distribution
mvn clean install
````
## Run adapter tests
### Wildfly
````
# Prepare servers
mvn -f testsuite/integration-arquillian/servers/pom.xml clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
# Run tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-wildfly
````
### JBoss Fuse 6.3
----------------------------------------
1) Download JBoss Fuse 6.3 to your filesystem. It can be downloaded from http://origin-repository.jboss.org/nexus/content/groups/m2-proxy/org/jboss/fuse/jboss-fuse-karaf
Assumed you downloaded `jboss-fuse-karaf-6.3.0.redhat-229.zip`
2) Install to your local maven repository and change the properties according to your env (This step can be likely avoided if you somehow configure your local maven settings to point directly to Fuse repo):
````
mvn install:install-file \
-DgroupId=org.jboss.fuse \
-DartifactId=jboss-fuse-karaf \
-Dversion=6.3.0.redhat-229 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-fuse-karaf-6.3.0.redhat-229.zip
````
3) Prepare Fuse and run the tests (change props according to your environment, versions etc):
````
# Prepare Fuse server
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229 \
-Dapp.server.karaf.update.config=true \
-Dmaven.local.settings=$HOME/.m2/settings.xml \
-Drepositories=,http://download.eng.bos.redhat.com/brewroot/repos/sso-7.1-build/latest/maven/ \
-Dmaven.repo.local=$HOME/.m2/repository
# Run the Fuse adapter tests
mvn -f testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-fuse63 \
-Dfuse63.version=6.3.0.redhat-229
````
### EAP6 with Hawtio
1) Download JBoss EAP 6.4.0.GA zip
2) Install to your local maven repository and change the properties according to your env (This step can be likely avoided if you somehow configure your local maven settings to point directly to EAP repo):
````
mvn install:install-file \
-DgroupId=org.jboss.as \
-DartifactId=jboss-as-dist \
-Dversion=7.5.0.Final-redhat-21 \
-Dpackaging=zip \
-Dfile=/mydownloads/jboss-eap-6.4.0.zip
````
3) Download Fuse EAP installer (for example from http://origin-repository.jboss.org/nexus/content/groups/m2-proxy/com/redhat/fuse/eap/fuse-eap-installer/6.3.0.redhat-220/ )
4) Install previously downloaded file manually
````
mvn install:install-file \
-DgroupId=com.redhat.fuse.eap \
-DartifactId=fuse-eap-installer \
-Dversion=6.3.0.redhat-220 \
-Dpackaging=jar \
-Dfile=/fuse-eap-installer-6.3.0.redhat-220.jar
````
5) Prepare EAP6 with Hawtio and run the test
````
# Prepare EAP6 and deploy hawtio
mvn -f testsuite/integration-arquillian/servers \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse \
-Dapp.server.jboss.version=7.5.0.Final-redhat-21 \
-Dfuse.installer.version=6.3.0.redhat-220
# Run the test
mvn -f testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml \
clean install \
-Pauth-server-wildfly \
-Papp-server-eap6-fuse
````
## Migration test
### DB migration test
This test will:
- start Keycloak 1.9.8
- import realm and some data to MySQL DB
- stop Keycloak 1.9.8
- start latest KEycloak, which automatically updates DB from 1.9.8
- Do some test that data are correct
1) Prepare MySQL DB and ensure that MySQL DB is empty. See [../../misc/DatabaseTesting.md](../../misc/DatabaseTesting.md) for some hints for locally prepare Docker MySQL image.
2) Run the test (Update according to your DB connection, versions etc):
````
export DB_HOST=localhost
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,jpa,clean-jpa,auth-server-migration \
-Dtest=MigrationTest \
-Dmigration.mode=auto \
-Dmigrated.auth.server.version=1.9.8.Final \
-Djdbc.mvn.groupId=mysql \
-Djdbc.mvn.version=5.1.29 \
-Djdbc.mvn.artifactId=mysql-connector-java \
-Dkeycloak.connectionsJpa.url=jdbc:mysql://$DB_HOST/keycloak \
-Dkeycloak.connectionsJpa.user=keycloak \
-Dkeycloak.connectionsJpa.password=keycloak
````
### JSON export/import migration test
This will start latest Keycloak and import the realm JSON file, which was previously exported from Keycloak 1.9.8.Final
````
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly,migration-import \
-Dtest=MigrationTest \
-Dmigration.mode=import \
-Dmigrated.auth.server.version=1.9.8.Final
````
## Social Login
The social login tests require setup of all social networks including an example social user. These details can't be
shared as it would result in the clients and users eventually being blocked. By default these tests are skipped.
To run the full test you need to configure clients in Google, Facebook, GitHub, Twitter, LinkedIn, Microsoft and
StackOverflow. See the server administration guide for details on how to do that. Further, you also need to create a
sample user that can login to the social network.
The details should be added to a standard properties file. For some properties you can use shared common properties and
override when needed. Or you can specify these for all providers. All providers require at least clientId and
clientSecret (StackOverflow also requires clientKey).
An example social.properties file looks like:
common.username=sampleuser@example.org
common.password=commonpassword
common.profile.firstName=Foo
common.profile.lastName=Bar
common.profile.email=sampleuser@example.org
google.clientId=asdfasdfasdfasdfsadf
google.clientSecret=zxcvzxcvzxcvzxcv
facebook.clientId=asdfasdfasdfasdfsadf
facebook.clientSecret=zxcvzxcvzxcvzxcv
facebook.profile.lastName=Test
In the example above the common username, password and profile are shared for all providers, but Facebook has a
different last name.
Some providers actively block bots so you need to use a proper browser to test. Either Firefox or Chrome should work.
To run the tests run:
mvn -f testsuite/integration-arquillian/pom.xml \
clean install \
-Pauth-server-wildfly \
-Dtest=SocialLoginTest \
-Dbrowser=chrome \
-Dsocial.config=/path/to/social.properties
## Different Browsers
To run with Chrome add `-Dbrowser=chrome`. Depending on the Chrome version you have you may need to download the latest
chromedriver from https://sites.google.com/a/chromium.org/chromedriver/downloads and point to it with
`-Dwebdriver.chrome.driver=/path/to/chromedriver`.

View file

@ -4,6 +4,9 @@
For overview see the **Modules Overview** section at the bottom of this README.
## How to run tests
See the file [HOW-TO-RUN.md](HOW-TO-RUN.md) .
## Container Lifecycles

View file

@ -26,6 +26,7 @@ do
echo "Updating Config"
./client $CLIENT_AUTH -f update-config.cli
if [ $? -ne 0 ]; then
echo "Call update-config.cli failed!";
RESULT=1;
else
./client $CLIENT_AUTH config:list | grep org.ops4j.pax.url.mvn.
@ -34,12 +35,16 @@ do
echo "Installing features."
./client $CLIENT_AUTH -f install-features.cli
if [ $? -ne 0 ]; then RESULT=1; fi
if [ $? -ne 0 ]; then
echo "Call install-features.cli failed!";
RESULT=1;
fi
if "$UPDATE_CONFIG" == "true"; then
echo "Updating Config - Keycloak authentication"
./client $CLIENT_AUTH -f update-config-auth.cli
if [ $? -ne 0 ]; then
echo "Call update-config-auth.cli failed!";
RESULT=1;
fi
fi

View file

@ -35,12 +35,17 @@ import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAppServ
*/
public class DeploymentTargetModifier extends AnnotationDeploymentScenarioGenerator {
// Will be replaced in runtime by real auth-server-container
public static final String AUTH_SERVER_CURRENT = "auth-server-current";
protected final Logger log = Logger.getLogger(this.getClass());
@Override
public List<DeploymentDescription> generate(TestClass testClass) {
List<DeploymentDescription> deployments = super.generate(testClass);
checkAuthServerTestDeployment(deployments, testClass);
String appServerQualifier = getAppServerQualifier(
testClass.getJavaClass());
@ -56,4 +61,17 @@ public class DeploymentTargetModifier extends AnnotationDeploymentScenarioGenera
return deployments;
}
private void checkAuthServerTestDeployment(List<DeploymentDescription> descriptions, TestClass testClass) {
for (DeploymentDescription deployment : descriptions) {
if (deployment.getTarget() != null) {
String containerQualifier = deployment.getTarget().getName();
if (AUTH_SERVER_CURRENT.equals(containerQualifier)) {
String authServerQualifier = AuthServerTestEnricher.AUTH_SERVER_CONTAINER;
log.infof("Setting target container for deployment %s.%s: %s", testClass.getName(), deployment.getName(), authServerQualifier);
deployment.setTarget(new TargetDescription(authServerQualifier));
}
}
}
}
}

View file

@ -18,6 +18,7 @@
package org.keycloak.testsuite.arquillian;
import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
import org.jboss.arquillian.container.osgi.OSGiApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider;
import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator;
@ -63,7 +64,8 @@ public class KeycloakArquillianExtension implements LoadableExtension {
builder
.override(ResourceProvider.class, URLResourceProvider.class, URLProvider.class)
.override(ResourceProvider.class, CustomizableURLResourceProvider.class, URLProvider.class)
.override(ResourceProvider.class, ContainerCustomizableURLResourceProvider.class, URLProvider.class);
.override(ResourceProvider.class, ContainerCustomizableURLResourceProvider.class, URLProvider.class)
.override(ApplicationArchiveProcessor.class, OSGiApplicationArchiveProcessor.class, KeycloakOSGiApplicationArchiveProcessor.class);
}

View file

@ -0,0 +1,56 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.arquillian;
import org.jboss.arquillian.container.osgi.OSGiApplicationArchiveProcessor;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.logging.Logger;
import org.jboss.shrinkwrap.api.Archive;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class KeycloakOSGiApplicationArchiveProcessor extends OSGiApplicationArchiveProcessor {
private static final Logger log = Logger.getLogger(KeycloakOSGiApplicationArchiveProcessor.class);
// We want to ignore OSGI for exampleAdapter tests
@Override
public void process(Archive<?> appArchive, TestClass testClass) {
Class<?> clazz = testClass.getJavaClass();
boolean isExampleAdapterTest = isExampleAdapterTest(clazz);
if (isExampleAdapterTest) {
log.infof("Ignore OSGiApplicationArchiveProcessor for test %s", clazz.getName());
} else {
super.process(appArchive, testClass);
}
}
public static boolean isExampleAdapterTest(Class<?> clazz) {
Class<?> parent = clazz;
while (true) {
parent = parent.getSuperclass();
if (parent == null) {
return false;
} else if (parent.getName().equals("org.keycloak.testsuite.adapter.AbstractExampleAdapterTest")) {
return true;
}
}
}
}

View file

@ -63,6 +63,10 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
return RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build("test").toString();
}
public String getPath(String realm) {
return RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build(realm).toString();
}
public void updateProfile(String firstName, String lastName, String email) {
firstNameInput.clear();
firstNameInput.sendKeys(firstName);
@ -141,6 +145,10 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
driver.navigate().to(getPath());
}
public void open(String realm) {
driver.navigate().to(getPath(realm));
}
public void backToApplication() {
backToApplicationLink.click();
}

View file

@ -41,12 +41,18 @@ public class LoginUpdateProfilePage extends AbstractPage {
private WebElement loginErrorMessage;
public void update(String firstName, String lastName, String email) {
if (firstName != null) {
firstNameInput.clear();
firstNameInput.sendKeys(firstName);
}
if (lastName != null) {
lastNameInput.clear();
lastNameInput.sendKeys(lastName);
}
if (email != null) {
emailInput.clear();
emailInput.sendKeys(email);
}
submitButton.click();
}

View file

@ -116,6 +116,7 @@ public abstract class AbstractFuseExampleAdapterTest extends AbstractExampleAdap
testRealmLoginPage.form().login("admin", "password");
assertCurrentUrlStartsWith(adminInterface);
assertTrue(driver.getPageSource().contains("Hello admin!"));
assertTrue(driver.getPageSource().contains("This second sentence is returned from a Camel RestDSL endpoint"));
customerListing.navigateTo();
customerListing.clickLogOut();

View file

@ -233,4 +233,24 @@ public abstract class AbstractUserAttributeMapperTest extends AbstractBaseBroker
.build()
);
}
@Test
public void testAddBasicMappingMultipleValues() {
testValueMapping(ImmutableMap.<String, List<String>>builder()
.build(),
ImmutableMap.<String, List<String>>builder()
.put(ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("second value").add("second value 2").build())
.build()
);
}
@Test
public void testDeleteBasicMappingMultipleValues() {
testValueMapping(ImmutableMap.<String, List<String>>builder()
.put(ATTRIBUTE_TO_MAP_NAME, ImmutableList.<String>builder().add("second value").add("second value 2").build())
.build(),
ImmutableMap.<String, List<String>>builder()
.build()
);
}
}

View file

@ -0,0 +1,232 @@
package org.keycloak.testsuite.broker;
import org.jboss.arquillian.graphene.Graphene;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.arquillian.graphene.wait.WebDriverWait;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.common.Profile;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.cli.exec.ExecutionException;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
import org.keycloak.testsuite.util.IdentityProviderBuilder;
import org.keycloak.testsuite.util.RealmBuilder;
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
import java.io.FileInputStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
/**
* Created by st on 19.01.17.
*/
public class SocialLoginTest extends AbstractKeycloakTest {
public static final String SOCIAL_CONFIG = "social.config";
private static Properties config = new Properties();
@Page
public AccountUpdateProfilePage account;
@Page
public LoginPage loginPage;
@Page
public LoginUpdateProfilePage updateProfilePage;
@BeforeClass
public static void loadConfig() throws Exception {
assumeTrue(System.getProperties().containsKey(SOCIAL_CONFIG));
config.load(new FileInputStream(System.getProperty(SOCIAL_CONFIG)));
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation rep = RealmBuilder.create().name("social").build();
List<IdentityProviderRepresentation> idps = new LinkedList<>();
rep.setIdentityProviders(idps);
idps.add(buildIdp("google"));
idps.add(buildIdp("facebook"));
idps.add(buildIdp("github"));
idps.add(buildIdp("twitter"));
idps.add(buildIdp("linkedin"));
idps.add(buildIdp("microsoft"));
idps.add(buildIdp("stackoverflow"));
testRealms.add(rep);
}
@Test
public void googleLogin() throws InterruptedException {
account.open("social");
loginPage.clickSocial("google");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("Email")));
driver.findElement(By.id("Email")).sendKeys(config.getProperty("google.username", config.getProperty("common.username")));
driver.findElement(By.id("next")).click();
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("Passwd")));
driver.findElement(By.id("Passwd")).sendKeys(config.getProperty("google.password", config.getProperty("common.password")));
driver.findElement(By.id("signIn")).click();
Graphene.waitGui().until(ExpectedConditions.elementToBeClickable(By.id("submit_approve_access")));
driver.findElement(By.id("submit_approve_access")).click();
assertEquals(config.getProperty("google.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("google.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("google.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void faceBookLogin() {
account.open("social");
loginPage.clickSocial("facebook");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("email")));
driver.findElement(By.id("email")).sendKeys(config.getProperty("facebook.username", config.getProperty("common.username")));
driver.findElement(By.id("pass")).sendKeys(config.getProperty("facebook.password", config.getProperty("common.password")));
driver.findElement(By.id("loginbutton")).click();
assertEquals(config.getProperty("facebook.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("facebook.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("facebook.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void githubLogin() {
account.open("social");
loginPage.clickSocial("github");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("login_field")));
driver.findElement(By.id("login_field")).sendKeys(config.getProperty("github.username", config.getProperty("common.username")));
driver.findElement(By.id("password")).sendKeys(config.getProperty("github.password", config.getProperty("common.password")));
driver.findElement(By.name("commit")).click();
assertEquals(config.getProperty("github.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("github.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("github.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void twitterLogin() {
account.open("social");
loginPage.clickSocial("twitter");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("username_or_email")));
driver.findElement(By.id("username_or_email")).sendKeys(config.getProperty("twitter.username", config.getProperty("common.username")));
driver.findElement(By.id("password")).sendKeys(config.getProperty("twitter.password", config.getProperty("common.password")));
driver.findElement(By.id("allow")).click();
assertTrue(updateProfilePage.isCurrent());
assertEquals(config.getProperty("twitter.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("twitter.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals("", updateProfilePage.getEmail());
updateProfilePage.update(null, null, "keycloakey@gmail.com");
assertEquals(config.getProperty("twitter.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("twitter.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("twitter.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void linkedinLogin() {
account.open("social");
loginPage.clickSocial("linkedin");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("session_key-oauth2SAuthorizeForm")));
driver.findElement(By.id("session_key-oauth2SAuthorizeForm")).sendKeys(config.getProperty("linkedin.username", config.getProperty("common.username")));
driver.findElement(By.id("session_password-oauth2SAuthorizeForm")).sendKeys(config.getProperty("linkedin.password", config.getProperty("common.password")));
driver.findElement(By.name("authorize")).click();
assertEquals(config.getProperty("linkedin.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("linkedin.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("linkedin.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void microsoftLogin() {
account.open("social");
loginPage.clickSocial("microsoft");
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("loginfmt")));
driver.findElement(By.name("loginfmt")).sendKeys(config.getProperty("microsoft.username", config.getProperty("common.username")));
driver.findElement(By.xpath("//input[@value='Next']")).click();
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("passwd")));
driver.findElement(By.name("passwd")).sendKeys(config.getProperty("microsoft.password", config.getProperty("common.password")));
driver.findElement(By.xpath("//input[@value='Sign in']")).click();
assertEquals(config.getProperty("microsoft.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("microsoft.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("microsoft.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
@Test
public void stackoverflowLogin() {
account.open("social");
loginPage.clickSocial("stackoverflow");
Graphene.waitModel().until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[@title='log in with Stack_Exchange']")));
driver.findElement(By.xpath("//a[@title='log in with Stack_Exchange']")).click();
driver.switchTo().frame(driver.findElement(By.id("affiliate-signin-iframe")));
Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("email")));
driver.findElement(By.name("email")).sendKeys(config.getProperty("stackoverflow.username", config.getProperty("common.username")));
driver.findElement(By.name("password")).sendKeys(config.getProperty("stackoverflow.password", config.getProperty("common.password")));
driver.findElement(By.xpath("//input[@value='Sign In']")).click();
assertEquals(config.getProperty("stackoverflow.profile.firstName", config.getProperty("common.profile.firstName")), updateProfilePage.getFirstName());
assertEquals(config.getProperty("stackoverflow.profile.lastName", config.getProperty("common.profile.lastName")), updateProfilePage.getLastName());
assertEquals("", updateProfilePage.getEmail());
updateProfilePage.update(null, null, "keycloakey@gmail.com");
assertEquals(config.getProperty("stackoverflow.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
assertEquals(config.getProperty("stackoverflow.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
assertEquals(config.getProperty("stackoverflow.profile.email", config.getProperty("common.profile.email")), account.getEmail());
}
private IdentityProviderRepresentation buildIdp(String id) {
IdentityProviderRepresentation idp = IdentityProviderBuilder.create().alias(id).providerId(id).build();
idp.setEnabled(true);
idp.getConfig().put("clientId", config.getProperty(id + ".clientId"));
idp.getConfig().put("clientSecret", config.getProperty(id + ".clientSecret"));
if (id.equals("stackoverflow")) {
idp.getConfig().put("key", config.getProperty(id + ".clientKey"));
}
return idp;
}
}

View file

@ -23,6 +23,7 @@ import java.util.stream.Collectors;
import javax.ws.rs.NotFoundException;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before;
import org.junit.Test;
@ -52,6 +53,7 @@ import org.keycloak.representations.idm.authorization.PolicyRepresentation;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.arquillian.DeploymentTargetModifier;
import org.keycloak.testsuite.arquillian.migration.Migration;
import org.keycloak.testsuite.runonserver.RunHelpers;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
@ -78,6 +80,7 @@ public class MigrationTest extends AbstractKeycloakTest {
private RealmResource masterRealm;
@Deployment
@TargetsContainer(DeploymentTargetModifier.AUTH_SERVER_CURRENT)
public static WebArchive deploy() {
return RunOnServerDeployment.create();
}
@ -361,6 +364,9 @@ public class MigrationTest extends AbstractKeycloakTest {
}
private void testOfflineTokenLogin() {
if (isImportMigrationMode()) {
log.info("Skip offline token login test in the 'import' migrationMode");
} else {
log.info("test login with old offline token");
String oldOfflineToken = suiteContext.getMigrationContext().getOfflineToken();
Assert.assertNotNull(oldOfflineToken);
@ -371,4 +377,14 @@ public class MigrationTest extends AbstractKeycloakTest {
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
assertEquals("migration-test-user", accessToken.getPreferredUsername());
}
}
private String getMigrationMode() {
return System.getProperty("migration.mode");
}
private boolean isImportMigrationMode() {
String mode = getMigrationMode();
return "import".equals(mode);
}
}

View file

@ -465,6 +465,9 @@ public class OfflineTokenTest extends AbstractKeycloakTest {
// Set the time offset, so that "normal" userSession expires
setTimeOffset(86400);
// Remove expired sessions. This will remove "normal" userSession
testingClient.testing().removeUserSessions(appRealm.toRepresentation().getId());
// Refresh with the offline token
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "secret1");

View file

@ -24,7 +24,7 @@
<parent>
<groupId>org.keycloak.testsuite</groupId>
<artifactId>integration-arquillian-tests-other</artifactId>
<version>2.5.1.Final-SNAPSHOT</version>
<version>3.0.0.CR1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -323,7 +323,8 @@
</java-opts>
<execute-commands>
<scripts>
<script>${jbossHome}/bin/migrate-domain.cli</script>
<script>${jbossHome}/bin/migrate-domain-standalone.cli</script>
<script>${jbossHome}/bin/migrate-domain-clustered.cli</script>
</scripts>
</execute-commands>
</configuration>

View file

@ -0,0 +1,163 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.federation.storage.ldap;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.UserStorageProviderModel;
import org.keycloak.storage.ldap.LDAPStorageProvider;
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.LDAPRule;
/**
* Test for special scenarios, which don't work on MSAD (eg. renaming user RDN to "sn=john2" )
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class LDAPNoMSADTest {
private static final Logger log = Logger.getLogger(LDAPProvidersIntegrationTest.class);
// Skip this test on MSAD
private static LDAPRule ldapRule = new LDAPRule((Map<String, String> ldapConfig) -> {
String vendor = ldapConfig.get(LDAPConstants.VENDOR);
return (vendor.equals(LDAPConstants.VENDOR_ACTIVE_DIRECTORY));
});
private static ComponentModel ldapModel = null;
private static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
LDAPTestUtils.addLocalUser(manager.getSession(), appRealm, "marykeycloak", "mary@test.com", "password-app");
MultivaluedHashMap<String,String> ldapConfig = LDAPTestUtils.getLdapRuleConfig(ldapRule);
ldapConfig.putSingle(LDAPConstants.SYNC_REGISTRATIONS, "true");
ldapConfig.putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString());
UserStorageProviderModel model = new UserStorageProviderModel();
model.setLastSync(0);
model.setChangedSyncPeriod(-1);
model.setFullSyncPeriod(-1);
model.setName("test-ldap");
model.setPriority(0);
model.setProviderId(LDAPStorageProviderFactory.PROVIDER_NAME);
model.setConfig(ldapConfig);
ldapModel = appRealm.addComponentModel(model);
LDAPTestUtils.addZipCodeLDAPMapper(appRealm, ldapModel);
// Delete all LDAP users and add some new for testing
LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
LDAPTestUtils.removeAllLDAPUsers(ldapFedProvider, appRealm);
LDAPObject john = LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
LDAPTestUtils.updateLDAPPassword(ldapFedProvider, john, "Password1");
LDAPObject existing = LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "existing", "Existing", "Foo", "existing@email.org", null, "5678");
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
}
});
@ClassRule
public static TestRule chain = RuleChain
.outerRule(ldapRule)
.around(keycloakRule);
// KEYCLOAK-4364
@Test
public void testUpdateWithUnmappedRdnAttribute() {
KeycloakSession session = keycloakRule.startSession();
ComponentModel snMapper = null;
try {
// Create LDAP user with "sn" attribute in RDN like "sn=johnkeycloak2,ou=People,dc=domain,dc=com"
RealmModel appRealm = session.realms().getRealmByName("test");
LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
LDAPObject john2 = LDAPTestUtils.addLDAPUser(ldapProvider, appRealm, "johnkeycloak2", "john2", "Doe2", "john2@email.org", null, "4321");
john2.setRdnAttributeName("sn");
ldapProvider.getLdapIdentityStore().update(john2);
// Remove "sn" mapper
List<ComponentModel> components = appRealm.getComponents(ldapModel.getId(), LDAPStorageMapper.class.getName());
for (ComponentModel mapper : components) {
if (mapper.getName().equals("last name")) {
snMapper = mapper;
break;
}
}
Assert.assertNotNull(snMapper);
appRealm.removeComponent(snMapper);
} finally {
keycloakRule.stopSession(session, true);
}
// Try to update johnkeycloak2 user. It shouldn't try to update DN
session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
UserModel johnkeycloak2 = session.users().getUserByUsername("johnkeycloak2", appRealm);
Assert.assertNotNull(johnkeycloak2);
johnkeycloak2.setFirstName("foo2");
johnkeycloak2.setLastName("foo");
} finally {
keycloakRule.stopSession(session, true);
}
// Re-create "sn" mapper back
session = keycloakRule.startSession();
try {
RealmModel appRealm = session.realms().getRealmByName("test");
snMapper.setId(null);
appRealm.addComponentModel(snMapper);
} finally {
keycloakRule.stopSession(session, true);
}
}
}