keycloak-aplcache
Changes
.travis.yml 2(+1 -1)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java 4(+4 -0)
adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java 1(+1 -0)
adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java 1(+1 -0)
adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java 7(+7 -0)
adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties 2(+2 -0)
adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java 9(+9 -0)
adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties 2(+2 -0)
examples/cordova/www/index.html 2(+1 -1)
pom.xml 22(+14 -8)
README.md 6(+3 -3)
saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java 37(+35 -2)
services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java 3(+2 -1)
testsuite/integration/pom.xml 4(+0 -4)
testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java 7(+7 -0)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java 25(+23 -2)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java 27(+26 -1)
testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/DisableAuthorizationSettingsTest.java 15(+15 -0)
themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html 14(+14 -0)
travis-run-tests.sh 2(+2 -0)
Details
.travis.yml 2(+1 -1)
diff --git a/.travis.yml b/.travis.yml
index 57147b0..ec6ed80 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,7 +25,7 @@ before_script:
- export MAVEN_SKIP_RC=true
install:
- - travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTests=true -B -V -q
+ - travis_wait 60 mvn install --no-snapshot-updates -Pdistribution -DskipTestsuite -B -V -q
script:
- ./travis-run-tests.sh $TESTS
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
index 472afb7..7f86ba1 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
@@ -101,6 +101,7 @@ public class AuthenticatedActionsHandler {
if (!deployment.isCors()) return false;
KeycloakSecurityContext securityContext = facade.getSecurityContext();
String origin = facade.getRequest().getHeader(CorsHeaders.ORIGIN);
+ String exposeHeaders = deployment.getCorsExposedHeaders();
String requestOrigin = UriUtils.getOrigin(facade.getRequest().getURI());
log.debugv("Origin: {0} uri: {1}", origin, facade.getRequest().getURI());
if (securityContext != null && origin != null && !origin.equals(requestOrigin)) {
@@ -124,6 +125,9 @@ public class AuthenticatedActionsHandler {
facade.getResponse().setStatus(200);
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
+ if (exposeHeaders != null) {
+ facade.getResponse().setHeader(CorsHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, exposeHeaders);
+ }
} else {
log.debugv("cors validation not needed as we're not a secure session or origin header was null: {0}", facade.getRequest().getURI());
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java
index 715af3d..416c392 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/CorsHeaders.java
@@ -30,4 +30,5 @@ public interface CorsHeaders {
String ORIGIN = "Origin";
String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
+ String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index ba7bc5d..31f842c 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -73,6 +73,7 @@ public class KeycloakDeployment {
protected int corsMaxAge = -1;
protected String corsAllowedHeaders;
protected String corsAllowedMethods;
+ protected String corsExposedHeaders;
protected boolean exposeToken;
protected boolean alwaysRefreshToken;
protected boolean registerNodeAtStartup;
@@ -325,6 +326,14 @@ public class KeycloakDeployment {
this.corsAllowedMethods = corsAllowedMethods;
}
+ public String getCorsExposedHeaders() {
+ return corsExposedHeaders;
+ }
+
+ public void setCorsExposedHeaders(String corsExposedHeaders) {
+ this.corsExposedHeaders = corsExposedHeaders;
+ }
+
public boolean isExposeToken() {
return exposeToken;
}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 2fd9276..a651753 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -96,6 +96,7 @@ public class KeycloakDeploymentBuilder {
deployment.setCorsMaxAge(adapterConfig.getCorsMaxAge());
deployment.setCorsAllowedHeaders(adapterConfig.getCorsAllowedHeaders());
deployment.setCorsAllowedMethods(adapterConfig.getCorsAllowedMethods());
+ deployment.setCorsExposedHeaders(adapterConfig.getCorsExposedHeaders());
}
// https://tools.ietf.org/html/rfc7636
diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
index 233c1ed..a4f04ec 100644
--- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
+++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
@@ -53,6 +53,7 @@ public class KeycloakDeploymentBuilderTest {
assertEquals(1000, deployment.getCorsMaxAge());
assertEquals("POST, PUT, DELETE, GET", deployment.getCorsAllowedMethods());
assertEquals("X-Custom, X-Custom2", deployment.getCorsAllowedHeaders());
+ assertEquals("X-Custom3, X-Custom4", deployment.getCorsExposedHeaders());
assertTrue(deployment.isBearerOnly());
assertTrue(deployment.isPublicClient());
assertTrue(deployment.isEnableBasicAuth());
diff --git a/adapters/oidc/adapter-core/src/test/resources/keycloak.json b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
index 9f0a204..f53432f 100644
--- a/adapters/oidc/adapter-core/src/test/resources/keycloak.json
+++ b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
@@ -9,6 +9,7 @@
"cors-max-age": 1000,
"cors-allowed-methods": "POST, PUT, DELETE, GET",
"cors-allowed-headers": "X-Custom, X-Custom2",
+ "cors-exposed-headers": "X-Custom3, X-Custom4",
"bearer-only": true,
"public-client": true,
"enable-basic-auth": true,
diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js
index 3f09229..89b15b8 100755
--- a/adapters/oidc/js/src/main/resources/keycloak.js
+++ b/adapters/oidc/js/src/main/resources/keycloak.js
@@ -587,7 +587,7 @@
req.onreadystatechange = function () {
if (req.readyState == 4) {
- if (req.status == 200) {
+ if (req.status == 200 || fileLoaded(req)) {
var config = JSON.parse(req.responseText);
kc.authServerUrl = config['auth-server-url'];
@@ -633,6 +633,10 @@
return promise.promise;
}
+ function fileLoaded(xhr) {
+ return xhr.status == 0 && xhr.responseText && xhr.responseURL.startsWith('file:');
+ }
+
function setToken(token, refreshToken, idToken, timeLocal) {
if (kc.tokenTimeoutHandle) {
clearTimeout(kc.tokenTimeoutHandle);
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java
index e4ff988..a7676ea 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/SharedAttributeDefinitons.java
@@ -124,6 +124,12 @@ public class SharedAttributeDefinitons {
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
+ protected static final SimpleAttributeDefinition CORS_EXPOSED_HEADERS =
+ new SimpleAttributeDefinitionBuilder("cors-exposed-headers", ModelType.STRING, true)
+ .setXmlName("cors-exposed-headers")
+ .setAllowExpression(true)
+ .setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
+ .build();
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
.setXmlName("expose-token")
@@ -191,6 +197,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(CORS_MAX_AGE);
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
+ ATTRIBUTES.add(CORS_EXPOSED_HEADERS);
ATTRIBUTES.add(EXPOSE_TOKEN);
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties
index 6244b0c..71101a1 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/org/keycloak/subsystem/wf8/extension/LocalDescriptions.properties
@@ -39,6 +39,7 @@ keycloak.realm.client-key-password=n/a
keycloak.realm.cors-max-age=CORS max-age header
keycloak.realm.cors-allowed-headers=CORS allowed headers
keycloak.realm.cors-allowed-methods=CORS allowed methods
+keycloak.realm.cors-exposed-headers=CORS exposed headers
keycloak.realm.expose-token=Enable secure URL that exposes access token
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.realm.always-refresh-token=Refresh token on every single web request
@@ -73,6 +74,7 @@ keycloak.secure-deployment.client-key-password=n/a
keycloak.secure-deployment.cors-max-age=CORS max-age header
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
+keycloak.secure-deployment.cors-exposed-headers=CORS exposed headers
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
index e9839bc..cc51ec4 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
@@ -58,6 +58,7 @@
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -88,6 +89,7 @@
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java
index 02d14e5..fafed42 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/SharedAttributeDefinitons.java
@@ -124,6 +124,12 @@ public class SharedAttributeDefinitons {
.setAllowExpression(true)
.setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
.build();
+ protected static final SimpleAttributeDefinition CORS_EXPOSED_HEADERS =
+ new SimpleAttributeDefinitionBuilder("cors-exposed-headers", ModelType.STRING, true)
+ .setXmlName("cors-exposed-headers")
+ .setAllowExpression(true)
+ .setValidator(new StringLengthValidator(1, Integer.MAX_VALUE, true, true))
+ .build();
protected static final SimpleAttributeDefinition EXPOSE_TOKEN =
new SimpleAttributeDefinitionBuilder("expose-token", ModelType.BOOLEAN, true)
.setXmlName("expose-token")
@@ -175,6 +181,8 @@ public class SharedAttributeDefinitons {
+
+
protected static final List<SimpleAttributeDefinition> ATTRIBUTES = new ArrayList<SimpleAttributeDefinition>();
static {
ATTRIBUTES.add(REALM_PUBLIC_KEY);
@@ -192,6 +200,7 @@ public class SharedAttributeDefinitons {
ATTRIBUTES.add(CORS_MAX_AGE);
ATTRIBUTES.add(CORS_ALLOWED_HEADERS);
ATTRIBUTES.add(CORS_ALLOWED_METHODS);
+ ATTRIBUTES.add(CORS_EXPOSED_HEADERS);
ATTRIBUTES.add(EXPOSE_TOKEN);
ATTRIBUTES.add(AUTH_SERVER_URL_FOR_BACKEND_REQUESTS);
ATTRIBUTES.add(ALWAYS_REFRESH_TOKEN);
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
index c0ca52e..a297c1d 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/extension/LocalDescriptions.properties
@@ -39,6 +39,7 @@ keycloak.realm.client-key-password=n/a
keycloak.realm.cors-max-age=CORS max-age header
keycloak.realm.cors-allowed-headers=CORS allowed headers
keycloak.realm.cors-allowed-methods=CORS allowed methods
+keycloak.realm.cors-exposed-headers=CORS exposed headers
keycloak.realm.expose-token=Enable secure URL that exposes access token
keycloak.realm.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.realm.always-refresh-token=Refresh token on every single web request
@@ -74,6 +75,7 @@ keycloak.secure-deployment.client-key-password=n/a
keycloak.secure-deployment.cors-max-age=CORS max-age header
keycloak.secure-deployment.cors-allowed-headers=CORS allowed headers
keycloak.secure-deployment.cors-allowed-methods=CORS allowed methods
+keycloak.secure-deployment.cors-exposed-headers=CORS exposed headers
keycloak.secure-deployment.expose-token=Enable secure URL that exposes access token
keycloak.secure-deployment.auth-server-url-for-backend-requests=URL to use to make background calls to auth server
keycloak.secure-deployment.always-refresh-token=Refresh token on every single web request
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
index 84399a3..8118209 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak_1_1.xsd
@@ -58,6 +58,7 @@
<xs:element name="disable-trust-manager" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="ssl-required" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="realm-public-key" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="auth-server-url-for-backend-requests" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="always-refresh-token" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
@@ -88,6 +89,7 @@
<xs:element name="cors-allowed-methods" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="bearer-only" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="cors-allowed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="cors-exposed-headers" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="resource" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="truststore" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="truststore-password" type="xs:string" minOccurs="0" maxOccurs="1"/>
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index f063962..ddd525b 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -29,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
"resource", "public-client", "credentials",
"use-resource-role-mappings",
- "enable-cors", "cors-max-age", "cors-allowed-methods",
+ "enable-cors", "cors-max-age", "cors-allowed-methods", "cors-exposed-headers",
"expose-token", "bearer-only", "autodetect-bearer-only",
"connection-pool-size",
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
index dfe4ae6..4a2b7e2 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/BaseAdapterConfig.java
@@ -33,7 +33,7 @@ import java.util.TreeMap;
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
"resource", "public-client", "credentials",
"use-resource-role-mappings",
- "enable-cors", "cors-max-age", "cors-allowed-methods",
+ "enable-cors", "cors-max-age", "cors-allowed-methods", "cors-exposed-headers",
"expose-token", "bearer-only", "autodetect-bearer-only", "enable-basic-auth"})
public class BaseAdapterConfig extends BaseRealmConfig {
@JsonProperty("resource")
@@ -48,6 +48,8 @@ public class BaseAdapterConfig extends BaseRealmConfig {
protected String corsAllowedHeaders;
@JsonProperty("cors-allowed-methods")
protected String corsAllowedMethods;
+ @JsonProperty("cors-exposed-headers")
+ protected String corsExposedHeaders;
@JsonProperty("expose-token")
protected boolean exposeToken;
@JsonProperty("bearer-only")
@@ -110,6 +112,14 @@ public class BaseAdapterConfig extends BaseRealmConfig {
this.corsAllowedMethods = corsAllowedMethods;
}
+ public String getCorsExposedHeaders() {
+ return corsExposedHeaders;
+ }
+
+ public void setCorsExposedHeaders(String corsExposedHeaders) {
+ this.corsExposedHeaders = corsExposedHeaders;
+ }
+
public boolean isExposeToken() {
return exposeToken;
}
diff --git a/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml b/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml
index e249722..50ea3d7 100644
--- a/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml
+++ b/distribution/feature-packs/adapter-feature-pack/feature-pack-build.xml
@@ -17,7 +17,7 @@
<build xmlns="urn:wildfly:feature-pack-build:1.0">
<dependencies>
- <artifact name="org.wildfly:wildfly-feature-pack" />
+ <artifact name="${feature.parent}" />
</dependencies>
<config>
<standalone template="configuration/standalone/template.xml" subsystems="configuration/standalone/subsystems.xml" output-file="standalone/configuration/standalone.xml" />
diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml
index e51f220..be9c989 100755
--- a/distribution/feature-packs/adapter-feature-pack/pom.xml
+++ b/distribution/feature-packs/adapter-feature-pack/pom.xml
@@ -61,12 +61,6 @@
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authz-client</artifactId>
</dependency>
-
- <dependency>
- <groupId>org.wildfly</groupId>
- <artifactId>wildfly-feature-pack</artifactId>
- <type>zip</type>
- </dependency>
</dependencies>
<build>
@@ -119,4 +113,52 @@
</plugins>
</build>
+
+ <profiles>
+ <profile>
+ <id>community</id>
+ <activation>
+ <property>
+ <name>!product</name>
+ </property>
+ </activation>
+
+ <properties>
+ <build-tools.version>${wildfly.build-tools.version}</build-tools.version>
+ <feature.parent>org.wildfly:wildfly-feature-pack</feature.parent>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.wildfly</groupId>
+ <artifactId>wildfly-feature-pack</artifactId>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+ </profile>
+
+ <profile>
+ <id>product</id>
+ <activation>
+ <property>
+ <name>product</name>
+ </property>
+ </activation>
+
+ <properties>
+ <build-tools.version>${eap.build-tools.version}</build-tools.version>
+ <feature.parent>org.jboss.eap:wildfly-feature-pack</feature.parent>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.eap</groupId>
+ <artifactId>wildfly-feature-pack</artifactId>
+ <version>${eap.version}</version>
+ <type>zip</type>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+
</project>
examples/cordova/www/index.html 2(+1 -1)
diff --git a/examples/cordova/www/index.html b/examples/cordova/www/index.html
index 296986d..78646df 100644
--- a/examples/cordova/www/index.html
+++ b/examples/cordova/www/index.html
@@ -20,7 +20,7 @@
<head>
<title>Authentication Example</title>
- <meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
+ <meta http-equiv="Content-Security-Policy" content="default-src * gap://ready; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8" src="keycloak.js"></script>
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserCredentialStore.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserCredentialStore.java
index d3539fe..a1a0cdb 100644
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserCredentialStore.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserCredentialStore.java
@@ -119,7 +119,7 @@ public class JpaUserCredentialStore implements UserCredentialStore {
entity.setUser(userRef);
em.persist(entity);
MultivaluedHashMap<String, String> config = cred.getConfig();
- if (config != null || !config.isEmpty()) {
+ if (config != null && !config.isEmpty()) {
for (String key : config.keySet()) {
List<String> values = config.getList(key);
pom.xml 22(+14 -8)
diff --git a/pom.xml b/pom.xml
index b14081a..4f128e2 100755
--- a/pom.xml
+++ b/pom.xml
@@ -45,7 +45,7 @@
<wildfly.build-tools.version>1.1.3.Final</wildfly.build-tools.version>
<wildfly11.version>11.0.0.Alpha1</wildfly11.version> <!-- for testing with wf11 pre-releases -->
<wildfly11.build-tools.version>1.1.8.Final</wildfly11.build-tools.version>
- <eap.version>7.1.0.Alpha1-redhat-16</eap.version>
+ <eap.version>7.1.0.Beta1-redhat-2</eap.version>
<eap.build-tools.version>1.1.8.Final</eap.build-tools.version>
<wildfly.core.version>2.0.10.Final</wildfly.core.version>
@@ -192,7 +192,6 @@
<module>adapters</module>
<module>authz</module>
<module>examples</module>
- <module>testsuite</module>
<module>misc</module>
</modules>
@@ -279,11 +278,6 @@
<version>${resteasy.version}</version>
</dependency>
<dependency>
- <groupId>org.jboss.resteasy</groupId>
- <artifactId>async-http-servlet-3.0</artifactId>
- <version>${resteasy.version}</version>
- </dependency>
- <dependency>
<groupId>org.jboss.spec.javax.xml.bind</groupId>
<artifactId>jboss-jaxb-api_2.2_spec</artifactId>
<version>${jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version}</version>
@@ -1541,11 +1535,23 @@
<product.name-html>\u003Cstrong\u003ERed Hat\u003C\u002Fstrong\u003E\u003Csup\u003E\u00AE\u003C\u002Fsup\u003E Single Sign On</product.name-html>
<product.version>${project.version}</product.version>
<product.default-profile>product</product.default-profile>
- <product.filename.version>7.1</product.filename.version>
+ <product.filename.version>7.2</product.filename.version>
</properties>
</profile>
<profile>
+ <id>testsuite</id>
+ <activation>
+ <property>
+ <name>!skipTestsuite</name>
+ </property>
+ </activation>
+ <modules>
+ <module>testsuite</module>
+ </modules>
+ </profile>
+
+ <profile>
<id>distribution</id>
<modules>
<module>distribution</module>
README.md 6(+3 -3)
diff --git a/README.md b/README.md
index a4454a0..c2efec5 100755
--- a/README.md
+++ b/README.md
@@ -41,10 +41,10 @@ To start Keycloak during development first build as specified above, then run:
mvn -f testsuite/integration/pom.xml exec:java -Pkeycloak-server
-To start Keycloak from the appliance distribution first build the distribution it as specified above, then run:
+To start Keycloak from the server distribution first build the distribution it as specified above, then run:
- tar xfz distribution/appliance-dist/target/keycloak-appliance-dist-all-<VERSION>.tar.gz
- cd keycloak-appliance-dist-all-<VERSION>/keycloak
+ tar xfz distribution/server-dist/target/keycloak-<VERSION>.tar.gz
+ cd keycloak-<VERSION>
bin/standalone.sh
To stop the server press `Ctrl + C`.
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
index 714ee3f..bb15d23 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtil.java
@@ -32,6 +32,7 @@ import org.keycloak.dom.saml.v2.assertion.StatementAbstractType;
import org.keycloak.dom.saml.v2.assertion.SubjectType;
import org.keycloak.dom.saml.v2.assertion.SubjectType.STSubType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
+import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.common.ErrorCodes;
import org.keycloak.saml.common.PicketLinkLogger;
import org.keycloak.saml.common.PicketLinkLoggerFactory;
@@ -287,6 +288,22 @@ public class AssertionUtil {
}
/**
+ * Given an assertion element, validate the signature.
+ */
+ public static boolean isSignatureValid(Element assertionElement, KeyLocator keyLocator) {
+ try {
+ Document doc = DocumentUtil.createDocument();
+ Node n = doc.importNode(assertionElement, true);
+ doc.appendChild(n);
+
+ return new SAML2Signature().validate(doc, keyLocator);
+ } catch (Exception e) {
+ logger.signatureAssertionValidationError(e);
+ }
+ return false;
+ }
+
+ /**
* Check whether the assertion has expired
*
* @param assertion
@@ -540,7 +557,23 @@ public class AssertionUtil {
return responseType.getAssertions().get(0).getAssertion();
}
- public static ResponseType decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ParsingException, ProcessingException, ConfigurationException {
+ public static boolean isAssertionEncrypted(ResponseType responseType) throws ProcessingException {
+ List<ResponseType.RTChoiceType> assertions = responseType.getAssertions();
+
+ if (assertions.isEmpty()) {
+ throw new ProcessingException("No assertion from response.");
+ }
+
+ ResponseType.RTChoiceType rtChoiceType = assertions.get(0);
+ return rtChoiceType.getEncryptedAssertion() != null;
+ }
+
+ /**
+ * This method modifies the given responseType, and replaces the encrypted assertion with a decrypted version.
+ *
+ * It returns the assertion element as it was decrypted. This can be used in sginature verification.
+ */
+ public static Element decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ParsingException, ProcessingException, ConfigurationException {
SAML2Response saml2Response = new SAML2Response();
Document doc = saml2Response.convert(responseType);
@@ -564,6 +597,6 @@ public class AssertionUtil {
responseType.replaceAssertion(oldID, new ResponseType.RTChoiceType(assertion));
- return responseType;
+ return decryptedDocumentElement;
}
}
\ No newline at end of file
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
index 31916ff..8510d47 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/util/XMLTimeUtil.java
@@ -130,7 +130,7 @@ public class XMLTimeUtil {
* @return
*/
public static long inMilis(int valueInMins) {
- return valueInMins * 60 * 1000;
+ return (long) valueInMins * 60 * 1000;
}
/**
@@ -241,4 +241,4 @@ public class XMLTimeUtil {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
index 9a28137..5feda2b 100755
--- a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
+++ b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
@@ -23,10 +23,10 @@ package org.keycloak.saml;
*/
public class SPMetadataDescriptor {
- public static String getSPDescriptor(String binding, String assertionEndpoint, String logoutEndpoint, boolean wantAuthnRequestsSigned, String entityId, String nameIDPolicyFormat, String signingCerts) {
+ public static String getSPDescriptor(String binding, String assertionEndpoint, String logoutEndpoint, boolean wantAuthnRequestsSigned, boolean wantAssertionsSigned, String entityId, String nameIDPolicyFormat, String signingCerts) {
String descriptor =
"<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + entityId + "\">\n" +
- " <SPSSODescriptor AuthnRequestsSigned=\"" + wantAuthnRequestsSigned + "\"\n" +
+ " <SPSSODescriptor AuthnRequestsSigned=\"" + wantAuthnRequestsSigned + "\" WantAssertionsSigned=\"" + wantAssertionsSigned + "\"\n" +
" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n";
if (wantAuthnRequestsSigned && signingCerts != null) {
descriptor += signingCerts;
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
index 52dd7ba..713a5bd 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/parsers/saml/SAMLParserTest.java
@@ -103,9 +103,9 @@ public class SAMLParserTest {
assertNotNull(rtChoiceType.getEncryptedAssertion());
PrivateKey privateKey = DerUtils.decodePrivateKey(Base64.decode(PRIVATE_KEY));
- ResponseType rtWithDecryptedAssertion = AssertionUtil.decryptAssertion(resp, privateKey);
+ AssertionUtil.decryptAssertion(resp, privateKey);
- rtChoiceType = rtWithDecryptedAssertion.getAssertions().get(0);
+ rtChoiceType = resp.getAssertions().get(0);
assertNotNull(rtChoiceType.getAssertion());
assertNull(rtChoiceType.getEncryptedAssertion());
}
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
index 72d84ee..5825f60 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLEndpoint.java
@@ -49,9 +49,12 @@ import org.keycloak.protocol.saml.SamlProtocolUtils;
import org.keycloak.saml.SAML2LogoutResponseBuilder;
import org.keycloak.saml.SAMLRequestParser;
import org.keycloak.saml.common.constants.GeneralConstants;
+import org.keycloak.saml.common.constants.JBossSAMLConstants;
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
import org.keycloak.saml.common.exceptions.ConfigurationException;
import org.keycloak.saml.common.exceptions.ProcessingException;
+import org.keycloak.saml.common.util.DocumentUtil;
+import org.keycloak.saml.processing.api.saml.v2.sig.SAML2Signature;
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
@@ -74,6 +77,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
+import javax.xml.namespace.QName;
import java.io.IOException;
import java.security.Key;
import java.security.cert.X509Certificate;
@@ -83,6 +87,8 @@ import java.util.List;
import org.keycloak.rotation.HardcodedKeyLocator;
import org.keycloak.rotation.KeyLocator;
import org.keycloak.saml.processing.core.util.KeycloakKeySamlExtensionGenerator;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import java.util.*;
@@ -344,7 +350,38 @@ public class SAMLEndpoint {
if (responseType.getAssertions() == null || responseType.getAssertions().isEmpty()) {
return callback.error(relayState, Messages.IDENTITY_PROVIDER_UNEXPECTED_ERROR);
}
- AssertionType assertion = AssertionUtil.getAssertion(responseType, keys.getPrivateKey());
+
+ boolean assertionIsEncrypted = AssertionUtil.isAssertionEncrypted(responseType);
+
+ if (config.isWantAssertionsEncrypted() && !assertionIsEncrypted) {
+ logger.error("The assertion is not encrypted, which is required.");
+ event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
+ event.error(Errors.INVALID_SAML_RESPONSE);
+ return ErrorPage.error(session, Messages.INVALID_REQUESTER);
+ }
+
+ Element assertionElement;
+
+ if (assertionIsEncrypted) {
+ // This methods writes the parsed and decrypted assertion back on the responseType parameter:
+ assertionElement = AssertionUtil.decryptAssertion(responseType, keys.getPrivateKey());
+ } else {
+ /* We verify the assertion using original document to handle cases where the IdP
+ includes whitespace and/or newlines inside tags. */
+ assertionElement = DocumentUtil.getElement(holder.getSamlDocument(), new QName(JBossSAMLConstants.ASSERTION.get()));
+ }
+
+ if (config.isWantAssertionsSigned() && config.isValidateSignature()) {
+ if (!AssertionUtil.isSignatureValid(assertionElement, getIDPKeyLocator())) {
+ logger.error("validation failed");
+ event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
+ event.error(Errors.INVALID_SIGNATURE);
+ return ErrorPage.error(session, Messages.INVALID_REQUESTER);
+ }
+ }
+
+ AssertionType assertion = responseType.getAssertions().get(0).getAssertion();
+
SubjectType subject = assertion.getSubject();
SubjectType.STSubType subType = subject.getSubType();
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
index 6a453b9..c28cda8 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProvider.java
@@ -236,6 +236,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
boolean wantAuthnRequestsSigned = getConfig().isWantAuthnRequestsSigned();
+ boolean wantAssertionsSigned = getConfig().isWantAssertionsSigned();
String entityId = getEntityId(uriInfo, realm);
String nameIDPolicyFormat = getConfig().getNameIDPolicyFormat();
@@ -247,7 +248,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
for (RsaKeyMetadata key : keys) {
addKeyInfo(keysString, key, KeyTypes.SIGNING.value());
}
- String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint, wantAuthnRequestsSigned, entityId, nameIDPolicyFormat, keysString.toString());
+ String descriptor = SPMetadataDescriptor.getSPDescriptor(authnBinding, endpoint, endpoint, wantAuthnRequestsSigned, wantAssertionsSigned, entityId, nameIDPolicyFormat, keysString.toString());
return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
}
diff --git a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
index d2a410b..4d200a0 100755
--- a/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
+++ b/services/src/main/java/org/keycloak/broker/saml/SAMLIdentityProviderConfig.java
@@ -121,6 +121,22 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
getConfig().put("wantAuthnRequestsSigned", String.valueOf(wantAuthnRequestsSigned));
}
+ public boolean isWantAssertionsSigned() {
+ return Boolean.valueOf(getConfig().get("wantAssertionsSigned"));
+ }
+
+ public void setWantAssertionsSigned(boolean wantAssertionsSigned) {
+ getConfig().put("wantAssertionsSigned", String.valueOf(wantAssertionsSigned));
+ }
+
+ public boolean isWantAssertionsEncrypted() {
+ return Boolean.valueOf(getConfig().get("wantAssertionsEncrypted"));
+ }
+
+ public void setWantAssertionsEncrypted(boolean wantAssertionsEncrypted) {
+ getConfig().put("wantAssertionsEncrypted", String.valueOf(wantAssertionsEncrypted));
+ }
+
public boolean isAddExtensionsElementWithKeyInfo() {
return Boolean.valueOf(getConfig().get("addExtensionsElementWithKeyInfo"));
}
diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/model/ClientBean.java b/services/src/main/java/org/keycloak/forms/login/freemarker/model/ClientBean.java
index d342f16..43dbdc0 100755
--- a/services/src/main/java/org/keycloak/forms/login/freemarker/model/ClientBean.java
+++ b/services/src/main/java/org/keycloak/forms/login/freemarker/model/ClientBean.java
@@ -46,6 +46,10 @@ public class ClientBean {
return client.getName();
}
+ public String getDescription() {
+ return client.getDescription();
+ }
+
public String getBaseUrl() {
return ResolveRelative.resolveRelativeUri(requestUri, client.getRootUrl(), client.getBaseUrl());
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 1014c0b..8984a4d 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -141,6 +141,15 @@ public class UserInfoEndpoint {
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
ClientSessionModel clientSession = session.sessions().getClientSession(token.getClientSession());
+ if( userSession == null ) {
+ userSession = session.sessions().getOfflineUserSession(realm, token.getSessionState());
+ if( AuthenticationManager.isOfflineSessionValid(realm, userSession)) {
+ clientSession = session.sessions().getOfflineClientSession(realm, token.getClientSession());
+ } else {
+ userSession = null;
+ clientSession = null;
+ }
+ }
if (userSession == null) {
event.error(Errors.USER_SESSION_NOT_FOUND);
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
index 6349953..bd109e6 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/SamlSPDescriptorClientInstallation.java
@@ -47,7 +47,8 @@ public class SamlSPDescriptorClientInstallation implements ClientInstallationPro
String nameIdFormat = samlClient.getNameIDFormat();
if (nameIdFormat == null) nameIdFormat = SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT;
String spCertificate = SPMetadataDescriptor.xmlKeyInfo(" ", null, samlClient.getClientSigningCertificate(), KeyTypes.SIGNING.value(), true);
- return SPMetadataDescriptor.getSPDescriptor(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get(), assertionUrl, logoutUrl, samlClient.requiresClientSignature(), client.getClientId(), nameIdFormat, spCertificate);
+ return SPMetadataDescriptor.getSPDescriptor(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get(), assertionUrl, logoutUrl,
+ samlClient.requiresClientSignature(), samlClient.requiresAssertionSignature(), client.getClientId(), nameIdFormat, spCertificate);
}
@Override
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 4585e16..12053e0 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -590,7 +590,7 @@ public class RealmAdminResource {
query.client(client);
}
- if (types != null & !types.isEmpty()) {
+ if (types != null && !types.isEmpty()) {
EventType[] t = new EventType[types.size()];
for (int i = 0; i < t.length; i++) {
t[i] = EventType.valueOf(types.get(i));
testsuite/integration/pom.xml 4(+0 -4)
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 4542557..cda3bbb 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -74,10 +74,6 @@
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
- <artifactId>async-http-servlet-3.0</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<exclusions>
<exclusion>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
index aa4ca66..6833b34 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
@@ -78,7 +78,7 @@ public class ValidationTest {
public void testBrokerExportDescriptor() throws Exception {
URL schemaFile = getClass().getResource("/schema/saml/v2/saml-schema-metadata-2.0.xsd");
Source xmlFile = new StreamSource(new ByteArrayInputStream(SPMetadataDescriptor.getSPDescriptor(
- "POST", "http://realm/assertion", "http://realm/logout", true, "test", SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT, KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate()
+ "POST", "http://realm/assertion", "http://realm/logout", true, false, "test", SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT, KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate()
).getBytes()), "SP Descriptor");
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
index 2796fc4..9639749 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
@@ -48,6 +48,9 @@ public class ModalDialog {
@FindBy(id = "name")
private WebElement nameInput;
+ @FindBy(className = "modal-body")
+ private WebElement message;
+
public void ok() {
waitForModalFadeIn(driver);
okButton.click();
@@ -70,4 +73,8 @@ public class ModalDialog {
nameInput.clear();
nameInput.sendKeys(name);
}
+
+ public WebElement getMessage() {
+ return message;
+ }
}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
index 37941b9..a71ef13 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -404,7 +404,7 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
int timeSkew = Integer.parseInt(jsConsoleTestAppPage.getTimeSkewValue().getText());
assertTrue("TimeSkew was: " + timeSkew + ", but should be ~0", timeSkew >= 0 - TIME_SKEW_TOLERANCE);
- assertTrue("TimeSkew was: " + timeSkew + ", but should be ~0", timeSkew <= TIME_SKEW_TOLERANCE);
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~0", timeSkew <= TIME_SKEW_TOLERANCE);
setTimeOffset(40);
jsConsoleTestAppPage.refreshToken();
@@ -414,7 +414,7 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
timeSkew = Integer.parseInt(jsConsoleTestAppPage.getTimeSkewValue().getText());
assertTrue("TimeSkew was: " + timeSkew + ", but should be ~-40", timeSkew + 40 >= 0 - TIME_SKEW_TOLERANCE);
- assertTrue("TimeSkew was: " + timeSkew + ", but should be ~-40", timeSkew + 40 <= TIME_SKEW_TOLERANCE);
+ assertTrue("TimeSkew was: " + timeSkew + ", but should be ~-40", timeSkew + 40 <= TIME_SKEW_TOLERANCE);
}
// KEYCLOAK-4179
@@ -526,6 +526,27 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
}
@Test
+ // KEYCLOAK-4503
+ public void initializeWithRefreshToken() {
+ oauth.realm(EXAMPLE);
+ oauth.clientId("js-console");
+ oauth.redirectUri("http://localhost:8280/js-console");
+ oauth.doLogin("user", "password");
+
+ String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+ String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+ String refreshToken = oauth.doRefreshTokenRequest(token, "password").getRefreshToken();
+
+ jsConsoleTestAppPage.navigateTo();
+ jsConsoleTestAppPage.setInput2(refreshToken);
+
+ jsConsoleTestAppPage.initWithRefreshToken();
+
+ waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Not Authenticated)");
+ waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().not().contains("Auth Success");
+ }
+
+ @Test
public void reentrancyCallbackTest() {
logInAndInit("standard");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index e6ec392..c57b64e 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -250,6 +250,24 @@ public class UserInfoTest extends AbstractKeycloakTest {
}
@Test
+ public void testSessionExpiredOfflineAccess() throws Exception {
+ Client client = ClientBuilder.newClient();
+
+ try {
+ AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client, true);
+
+ testingClient.testing().removeUserSessions("test");
+
+ Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken());
+
+ testSuccessfulUserInfoResponse(response);
+ response.close();
+ } finally {
+ client.close();
+ }
+ }
+
+ @Test
public void testUnsuccessfulUserInfoRequest() throws Exception {
Client client = ClientBuilder.newClient();
@@ -274,8 +292,12 @@ public class UserInfoTest extends AbstractKeycloakTest {
}
private AccessTokenResponse executeGrantAccessTokenRequest(Client client) {
+ return executeGrantAccessTokenRequest(client, false);
+ }
+
+ private AccessTokenResponse executeGrantAccessTokenRequest(Client client, boolean requestOfflineToken) {
UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
- URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
+ URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
String header = BasicAuthHelper.createHeader("test-app", "password");
@@ -283,6 +305,9 @@ public class UserInfoTest extends AbstractKeycloakTest {
form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
.param("username", "test-user@localhost")
.param("password", "password");
+ if( requestOfflineToken) {
+ form.param("scope", "offline_access");
+ }
Response response = grantTarget.request()
.header(HttpHeaders.AUTHORIZATION, header)
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/DisableAuthorizationSettingsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/DisableAuthorizationSettingsTest.java
index 3e3359e..0c60f0f 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/DisableAuthorizationSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authorization/DisableAuthorizationSettingsTest.java
@@ -17,6 +17,8 @@
package org.keycloak.testsuite.console.authorization;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
import org.junit.Test;
@@ -25,10 +27,13 @@ import org.junit.Test;
*/
public class DisableAuthorizationSettingsTest extends AbstractAuthorizationSettingsTest {
+ public static final String WARNING_MESSAGE = "Are you sure you want to disable authorization ? Once you save your changes, all authorization settings associated with this client will be removed. This operation can not be reverted.";
+
@Test
public void testDisableAuthorization() throws InterruptedException {
clientSettingsPage.navigateTo();
clientSettingsPage.form().setAuthorizationSettingsEnabled(false);
+ waitUntilElement(modalDialog.getMessage()).text().contains(WARNING_MESSAGE);
clientSettingsPage.form().confirmDisableAuthorizationSettings();
Thread.sleep(1000);
clientSettingsPage.form().save();
@@ -37,4 +42,14 @@ public class DisableAuthorizationSettingsTest extends AbstractAuthorizationSetti
clientSettingsPage.navigateTo();
assertFalse(clientSettingsPage.form().isAuthorizationSettingsEnabled());
}
+
+ @Test
+ public void testCancelDisablingAuthorization() throws InterruptedException {
+ clientSettingsPage.navigateTo();
+ clientSettingsPage.form().setAuthorizationSettingsEnabled(false);
+ waitUntilElement(modalDialog.getMessage()).text().contains(WARNING_MESSAGE);
+ modalDialog.cancel();
+ Thread.sleep(1000);
+ assertTrue(clientSettingsPage.form().isAuthorizationSettingsEnabled());
+ }
}
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index f0d569c..4e29ec3 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -894,10 +894,6 @@
<dependency>
<groupId>org.jboss.resteasy</groupId>
- <artifactId>async-http-servlet-3.0</artifactId>
- </dependency>
- <dependency>
- <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 175e39e..db61ff7 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -551,7 +551,11 @@ http-post-binding-for-authn-request.tooltip=Indicates whether the AuthnRequest m
http-post-binding-logout=HTTP-POST Binding Logout
http-post-binding-logout.tooltip=Indicates whether to respond to requests using HTTP-POST binding. If false, HTTP-REDIRECT binding will be used.
want-authn-requests-signed=Want AuthnRequests Signed
-want-authn-requests-signed.tooltip=Indicates whether the identity provider expects signed a AuthnRequest.
+want-authn-requests-signed.tooltip=Indicates whether the identity provider expects a signed AuthnRequest.
+want-assertions-signed=Want Assertions Signed
+want-assertions-signed.tooltip=Indicates whether this service provider expects a signed Assertion.
+want-assertions-encrypted=Want Assertions Encrypted
+want-assertions-encrypted.tooltip=Indicates whether this service provider expects an encrypted Assertion.
force-authentication=Force Authentication
identity-provider.force-authentication.tooltip=Indicates whether the identity provider must authenticate the presenter directly rather than rely on a previous security context.
validate-signature=Validate Signature
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index 58db5a0..734040e 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -1943,9 +1943,13 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location,
} else if (response.status) {
if (response.data && response.data.errorMessage) {
Notifications.error(response.data.errorMessage);
+ } else if (response.data && response.data.error_description) {
+ Notifications.error(response.data.error_description);
} else {
Notifications.error("An unexpected server error has occurred");
}
+ } else {
+ Notifications.error("No response from server.");
}
return $q.reject(response);
}
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index a2cbea4..315b8a5 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -437,9 +437,6 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
}).success(function(data, status, headers) {
Notifications.success("Keystore uploaded successfully.");
$location.url(redirectLocation);
- }).error(function(data) {
- var errorMsg = data['error_description'] ? data['error_description'] : 'The key store can not be uploaded. Please verify the file.';
- Notifications.error(errorMsg);
});
//.then(success, error, progress);
}
@@ -1229,12 +1226,6 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
}, $scope.clientEdit, function() {
$route.reload();
Notifications.success("Your changes have been saved to the client.");
- }, function(error) {
- if (error.status == 400 && error.data.error_description) {
- Notifications.error(error.data.error_description);
- } else {
- Notifications.error('Unexpected error when updating client');
- }
});
}
};
@@ -1348,12 +1339,6 @@ module.controller('CreateClientCtrl', function($scope, realm, client, templates,
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + "/clients/" + id);
Notifications.success("The client has been created.");
- }, function(error) {
- if (error.status == 400 && error.data.error_description) {
- Notifications.error(error.data.error_description);
- } else {
- Notifications.error('Unexpected error when creating client');
- }
});
};
@@ -1818,12 +1803,6 @@ module.controller('ClientProtocolMapperCtrl', function($scope, realm, serverInfo
mapper = angular.copy($scope.mapper);
$location.url("/realms/" + realm.realm + '/clients/' + client.id + "/mappers/" + $scope.model.mapper.id);
Notifications.success("Your changes have been saved.");
- }, function(error) {
- if (error.status == 400 && error.data.error_description) {
- Notifications.error(error.data.error_description);
- } else {
- Notifications.error('Unexpected error when updating protocol mapper');
- }
});
};
@@ -1890,14 +1869,6 @@ module.controller('ClientProtocolMapperCreateCtrl', function($scope, realm, serv
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + '/clients/' + client.id + "/mappers/" + id);
Notifications.success("Mapper has been created.");
- }, function(error) {
- if (error.status == 400 && error.data.error_description) {
- Notifications.error(error.data.error_description);
- } else if (error.status == 409 && error.data.errorMessage) {
- Notifications.error(error.data.errorMessage);
- } else {
- Notifications.error('Unexpected error when updating protocol mapper');
- }
});
};
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index 4f2a62f..d5b63c3 100644
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -1220,10 +1220,6 @@ module.controller('GenericKeystoreCtrl', function($scope, $location, Notificatio
$location.url("/realms/" + realm.realm + "/keys/providers/" + $scope.instance.providerId + "/" + id);
Notifications.success("The provider has been created.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
} else {
Components.update({realm: realm.realm,
@@ -1232,10 +1228,6 @@ module.controller('GenericKeystoreCtrl', function($scope, $location, Notificatio
$scope.instance, function () {
$route.reload();
Notifications.success("The provider has been updated.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
}
};
@@ -2478,10 +2470,6 @@ module.controller('ClientRegPolicyDetailCtrl', function($scope, realm, clientReg
var id = l.substring(l.lastIndexOf("/") + 1);
$location.url("/realms/" + realm.realm + "/client-registration/client-reg-policies/" + $scope.instance.providerId + "/" + id);
Notifications.success("The policy has been created.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
} else {
Components.update({realm: realm.realm,
@@ -2490,10 +2478,6 @@ module.controller('ClientRegPolicyDetailCtrl', function($scope, realm, clientReg
$scope.instance, function () {
$route.reload();
Notifications.success("The policy has been updated.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
}
};
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index 8f42618..13d8343 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -59,12 +59,6 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, cl
$scope.selectedClientMappings = [];
}
Notifications.success("Role mappings updated.");
- }).error(function(response) {
- if (response && response['error_description']) {
- Notifications.error(response['error_description']);
- } else {
- Notifications.error("Failed to remove role mapping");
- }
});
};
@@ -93,12 +87,6 @@ module.controller('UserRoleMappingCtrl', function($scope, $http, realm, user, cl
$scope.realmComposite = CompositeRealmRoleMapping.query({realm : realm.realm, userId : user.id});
$scope.realmRoles = AvailableRealmRoleMapping.query({realm : realm.realm, userId : user.id});
Notifications.success("Role mappings updated.");
- }).error(function(response) {
- if (response && response['error_description']) {
- Notifications.error(response['error_description']);
- } else {
- Notifications.error("Failed to remove role mapping");
- }
});
};
@@ -537,12 +525,6 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, $route, R
Notifications.success("The password has been reset");
$scope.password = null;
$scope.confirmPassword = null;
- }, function(response) {
- if (response.data && response.data['error_description']) {
- Notifications.error(response.data['error_description']);
- } else {
- Notifications.error("Failed to reset user password");
- }
});
}, function() {
$scope.password = null;
@@ -822,10 +804,6 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
$location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id);
Notifications.success("The provider has been created.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
} else {
console.log('update existing provider');
@@ -835,10 +813,6 @@ module.controller('GenericUserStorageCtrl', function($scope, $location, Notifica
$scope.instance, function () {
$route.reload();
Notifications.success("The provider has been updated.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
}
};
@@ -950,12 +924,6 @@ module.controller('UserGroupMembershipCtrl', function($scope, $route, realm, gro
UserGroupMapping.remove({realm: realm.realm, userId: user.id, groupId: $scope.selectedGroup.id}, function() {
Notifications.success('Removed group membership');
$route.reload();
- }, function(response) {
- if (response.data && response.data['error_description']) {
- Notifications.error(response.data['error_description']);
- } else {
- Notifications.error("Failed to leave group");
- }
});
};
@@ -1231,10 +1199,6 @@ module.controller('LDAPUserStorageCtrl', function($scope, $location, Notificatio
$location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id);
Notifications.success("The provider has been created.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
} else {
Components.update({realm: realm.realm,
@@ -1243,10 +1207,6 @@ module.controller('LDAPUserStorageCtrl', function($scope, $location, Notificatio
$scope.instance, function () {
$route.reload();
Notifications.success("The provider has been updated.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
}
};
@@ -1409,10 +1369,6 @@ module.controller('LDAPMapperCtrl', function($scope, $route, realm, provider, m
$scope.mapper, function () {
$route.reload();
Notifications.success("The mapper has been updated.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
};
@@ -1498,10 +1454,6 @@ module.controller('LDAPMapperCreateCtrl', function($scope, realm, provider, mapp
$location.url("/realms/" + realm.realm + "/ldap-mappers/" + $scope.mapper.parentId + "/mappers/" + id);
Notifications.success("The mapper has been created.");
- }, function (errorResponse) {
- if (errorResponse.data && errorResponse.data['error_description']) {
- Notifications.error(errorResponse.data['error_description']);
- }
});
};
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
index d764b90..3422752 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider.html
@@ -33,7 +33,7 @@
<caption class="hidden">{{:: 'table-of-identity-providers' | translate}}</caption>
<thead>
<tr>
- <th colspan="7" class="kc-table-actions">
+ <th colspan="8" class="kc-table-actions">
<div class="dropdown pull-right" data-ng-show="access.manageIdentityProviders">
<select class="form-control" ng-model="provider"
ng-options="p.name group by p.groupName for p in allProviders track by p.id"
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
index 9c79a47..aa6733a 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-saml.html
@@ -170,6 +170,20 @@
</div>
<kc-tooltip>{{:: 'want-authn-requests-signed.tooltip' | translate}}</kc-tooltip>
</div>
+ <div class="form-group">
+ <label class="col-md-2 control-label" for="wantAssertionsSigned">{{:: 'want-assertions-signed' | translate}}</label>
+ <div class="col-md-6">
+ <input ng-model="identityProvider.config.wantAssertionsSigned" id="wantAssertionsSigned" name="wantAssertionsSigned" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+ </div>
+ <kc-tooltip>{{:: 'want-assertions-signed.tooltip' | translate}}</kc-tooltip>
+ </div>
+ <div class="form-group">
+ <label class="col-md-2 control-label" for="wantAssertionsEncrypted">{{:: 'want-assertions-encrypted' | translate}}</label>
+ <div class="col-md-6">
+ <input ng-model="identityProvider.config.wantAssertionsEncrypted" id="wantAssertionsEncrypted" name="wantAssertionsEncrypted" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
+ </div>
+ <kc-tooltip>{{:: 'want-assertions-encrypted.tooltip' | translate}}</kc-tooltip>
+ </div>
<div class="form-group" data-ng-show="identityProvider.config.wantAuthnRequestsSigned == 'true'">
<label class="col-md-2 control-label" for="signatureAlgorithm">{{:: 'signature-algorithm' | translate}}</label>
<div class="col-sm-6">
travis-run-tests.sh 2(+2 -0)
diff --git a/travis-run-tests.sh b/travis-run-tests.sh
index cf5f03b..fd5e5e3 100755
--- a/travis-run-tests.sh
+++ b/travis-run-tests.sh
@@ -1,5 +1,7 @@
#!/bin/bash -e
+mvn install --no-snapshot-updates -DskipTests=true -f testsuite
+
if [ $1 == "old" ]; then
mvn test -B --no-snapshot-updates -f testsuite/integration
mvn test -B --no-snapshot-updates -f testsuite/jetty