From 2bba6af6d91975e6c26bce76ec43083fe69fa8db Mon Sep 17 00:00:00 2001 From: Cherian Mathew Date: Tue, 18 Oct 2016 22:51:38 +0200 Subject: [PATCH 01/21] Include programmatically created resources in the resource cache --- .../authorization/infinispan/CachedResourceStore.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java index f86de2f067..8696d8d11e 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java +++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java @@ -108,13 +108,9 @@ public class CachedResourceStore implements ResourceStore { @Override public List findByOwner(String ownerId) { - List cachedIds = this.cache.get(getResourceOwnerCacheKey(ownerId)); - if (cachedIds == null) { - for (Resource resource : getDelegate().findByOwner(ownerId)) { - updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true); - } - cachedIds = this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList()); + for (Resource resource : getDelegate().findByOwner(ownerId)) { + updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true); } return ((List) this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList())).stream().map(this::findById) From d7d91cfbc0a3793039c65f8fd8d56ae3cf82924f Mon Sep 17 00:00:00 2001 From: Cherian Mathew Date: Thu, 20 Oct 2016 15:50:57 +0200 Subject: [PATCH 02/21] Add client api for requesting entitlements with permission requests --- .../js/src/main/resources/keycloak-authz.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/adapters/oidc/js/src/main/resources/keycloak-authz.js b/adapters/oidc/js/src/main/resources/keycloak-authz.js index 4e4255637e..2ce9ba4465 100644 --- a/adapters/oidc/js/src/main/resources/keycloak-authz.js +++ b/adapters/oidc/js/src/main/resources/keycloak-authz.js @@ -118,12 +118,11 @@ /** * Obtains all entitlements from a Keycloak Server based on a give resourceServerId. */ - this.entitlement = function (resourceSeververId) { + this.entitlement = function (resourceSeververId, permissionRequests) { this.then = function (onGrant, onDeny, onError) { var request = new XMLHttpRequest(); - request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true); - request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token) + request.onreadystatechange = function () { if (request.readyState == 4) { @@ -149,7 +148,19 @@ } }; - request.send(null); + var erJson = null + + if(permissionRequests) { + request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true); + request.setRequestHeader("Content-type", "application/json"); + erJson = JSON.stringify(permissionRequests) + } else { + request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true); + } + + request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token) + request.send(erJson); + }; return this; From 94d4afa11cb0477f8c644db30175f76e514b16f5 Mon Sep 17 00:00:00 2001 From: Cherian Mathew Date: Thu, 20 Oct 2016 17:24:41 +0200 Subject: [PATCH 03/21] Refactor entitlement request argument name --- adapters/oidc/js/src/main/resources/keycloak-authz.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adapters/oidc/js/src/main/resources/keycloak-authz.js b/adapters/oidc/js/src/main/resources/keycloak-authz.js index 2ce9ba4465..843b11d9fb 100644 --- a/adapters/oidc/js/src/main/resources/keycloak-authz.js +++ b/adapters/oidc/js/src/main/resources/keycloak-authz.js @@ -118,7 +118,7 @@ /** * Obtains all entitlements from a Keycloak Server based on a give resourceServerId. */ - this.entitlement = function (resourceSeververId, permissionRequests) { + this.entitlement = function (resourceSeververId, entitlementRequest ) { this.then = function (onGrant, onDeny, onError) { var request = new XMLHttpRequest(); @@ -150,10 +150,10 @@ var erJson = null - if(permissionRequests) { + if(entitlementRequest) { request.open('POST', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true); request.setRequestHeader("Content-type", "application/json"); - erJson = JSON.stringify(permissionRequests) + erJson = JSON.stringify(entitlementRequest) } else { request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true); } From 25909b5e790be2f11a1030255ef549db454bc626 Mon Sep 17 00:00:00 2001 From: zschwarz Date: Thu, 27 Oct 2016 13:09:20 +0200 Subject: [PATCH 04/21] RHSSO-473 Add preview profile job to RH-SSO CI --- .../authorization/AbstractDefaultAuthzConfigAdapterTest.java | 5 +++++ .../authorization/AbstractPhotozExampleAdapterTest.java | 5 +++++ .../authorization/AbstractServletAuthzAdapterTest.java | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java index 87c0024b00..848f5c7a00 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java @@ -20,6 +20,7 @@ import org.jboss.arquillian.container.test.api.Deployer; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.BeforeClass; import org.junit.Test; import org.keycloak.admin.client.resource.AuthorizationResource; import org.keycloak.admin.client.resource.ClientResource; @@ -27,6 +28,7 @@ import org.keycloak.admin.client.resource.ClientsResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest; import java.io.File; @@ -47,6 +49,9 @@ public abstract class AbstractDefaultAuthzConfigAdapterTest extends AbstractExam private static final String REALM_NAME = "hello-world-authz"; private static final String RESOURCE_SERVER_ID = "hello-world-authz-service"; + @BeforeClass + public static void enabled() { ProfileAssume.assumePreview(); } + @ArquillianResource private Deployer deployer; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java index e89b950362..5b842bd2a6 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java @@ -22,6 +22,7 @@ import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.keycloak.admin.client.resource.AuthorizationResource; import org.keycloak.admin.client.resource.ClientResource; @@ -37,6 +38,7 @@ import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest; import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp; import org.keycloak.util.JsonSerialization; @@ -79,6 +81,9 @@ public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAd testRealmPage.setAuthRealm(REALM_NAME); } + @BeforeClass + public static void enabled() { ProfileAssume.assumePreview(); } + @Before public void beforePhotozExampleAdapterTest() throws FileNotFoundException { deleteAllCookiesForClientPage(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java index 7f61556de9..e843611db7 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java @@ -20,6 +20,7 @@ import org.jboss.arquillian.container.test.api.Deployer; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.test.api.ArquillianResource; import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.BeforeClass; import org.junit.Test; import org.keycloak.admin.client.resource.AuthorizationResource; import org.keycloak.admin.client.resource.ClientResource; @@ -33,6 +34,7 @@ import org.keycloak.representations.idm.RoleRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.authorization.PolicyRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest; import org.keycloak.testsuite.util.WaitUtils; import org.keycloak.util.JsonSerialization; @@ -63,6 +65,9 @@ public abstract class AbstractServletAuthzAdapterTest extends AbstractExampleAda private static final String REALM_NAME = "servlet-authz"; private static final String RESOURCE_SERVER_ID = "servlet-authz-app"; + @BeforeClass + public static void enabled() { ProfileAssume.assumePreview(); } + @ArquillianResource private Deployer deployer; From 89348af59e7378f04c1d7c65bc1e137bad05a32e Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Fri, 28 Oct 2016 12:06:53 -0400 Subject: [PATCH 05/21] KEYCLOAK-3281: Pressing Enter in Identity Provider form causes error --- .../base/admin/resources/js/controllers/realm.js | 2 +- .../partials/realm-identity-provider-oidc.html | 14 ++++++++++---- .../partials/realm-identity-provider-saml.html | 14 ++++++++++---- 3 files changed, 21 insertions(+), 9 deletions(-) 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 d0c2d0e8e1..ac19dacd4e 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 @@ -956,7 +956,7 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload id: $scope.identityProvider.internalId }, $scope.identityProvider, function () { $route.reload(); - Notifications.success("The " + $scope.identityProvider.alias + " provider has been update."); + Notifications.success("The " + $scope.identityProvider.alias + " provider has been updated."); }); } }; diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html index 80b4074793..c686283d5f 100755 --- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html +++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-oidc.html @@ -222,8 +222,11 @@ {{:: 'identity-provider.import-from-url.tooltip' | translate}} -
- +
+
+ +
+
@@ -238,8 +241,11 @@ {{files[0].name}}
-
- +
+ +
+ +
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 0ed66c6cd2..49f0e47976 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 @@ -191,8 +191,11 @@ {{:: 'saml.import-from-url.tooltip' | translate}} -
- +
+
+ +
+
@@ -206,8 +209,11 @@ {{files[0].name}}
-
- +
+ +
+ +
From 4bd567e610531abff160b71f21f5561452b08fac Mon Sep 17 00:00:00 2001 From: Vlasta Ramik Date: Mon, 31 Oct 2016 09:21:57 +0100 Subject: [PATCH 06/21] add profile to tests module for testing migration for productized version --- .../integration-arquillian/tests/pom.xml | 192 +++++++++--------- 1 file changed, 101 insertions(+), 91 deletions(-) diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index bfea8e39f4..4f8e9348c9 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -412,74 +412,73 @@ auth-server-migration + src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json -Dkeycloak.migration.action=import -Dkeycloak.migration.provider=singleFile - -Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json + -Dkeycloak.migration.file=${migration.import.file} -Dkeycloak.migration.strategy=OVERWRITE_EXISTING true - - - - maven-enforcer-plugin - - - - enforce - - - - - migrated.auth.server.version - - - migration.mode - - - - - - - - maven-dependency-plugin - - - unpack-migrated-auth-server-jboss - generate-resources - - unpack - - - - - org.keycloak.testsuite - integration-arquillian-migration-server - ${project.version} - zip - - - ${containers.home} - true - - - - - - maven-surefire-plugin - - - ${migrated.auth.server.version} - true - ${containers.home}/keycloak-${migrated.auth.server.version} - ${migration.import.props.previous} - - - - - + + + maven-enforcer-plugin + + + + enforce + + + + + migrated.auth.server.version + + + migration.mode + + + + + + + + maven-dependency-plugin + + + unpack-migrated-auth-server-jboss + generate-resources + + unpack + + + + + org.keycloak.testsuite + integration-arquillian-migration-server + ${project.version} + zip + + + ${containers.home} + true + + + + + + maven-surefire-plugin + + + ${migrated.auth.server.version} + true + ${containers.home}/keycloak-${migrated.auth.server.version} + ${migration.import.props.previous} + + + + @@ -492,47 +491,58 @@ + src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json -Dkeycloak.migration.action=import -Dkeycloak.migration.provider=singleFile - -Dkeycloak.migration.file=src/test/resources/migration-test/migration-realm-${migrated.auth.server.version}.json + -Dkeycloak.migration.file=${migration.import.file} -Dkeycloak.migration.strategy=OVERWRITE_EXISTING true - - - - maven-enforcer-plugin - - - - enforce - - - - - migrated.auth.server.version - - - - - - - - maven-surefire-plugin - - - ${migrated.auth.server.version} - ${migration.import.properties} - - - - - + + + maven-enforcer-plugin + + + + enforce + + + + + migrated.auth.server.version + + + + + + + + maven-surefire-plugin + + + ${migrated.auth.server.version} + ${migration.import.properties} + + + + + + + migration-productized + + + migrated.version.import.file.suffix + + + + src/test/resources/migration-test/migration-realm-${migrated.version.import.file.suffix}.json + + no-account From 446b57b827378f76f9bd066c862ee1844f0dd34e Mon Sep 17 00:00:00 2001 From: mhajas Date: Wed, 19 Oct 2016 10:48:21 +0200 Subject: [PATCH 07/21] KEYCLOAK-3841 Testing of Hawtio console on EAP6 + fuse integration --- .../app-server/jboss/common/add-hawtio.xsl | 40 +++ .../app-server/jboss/common/install-fuse.sh | 12 + .../jboss/common/keycloak-hawtio-client.json | 7 + .../jboss/common/keycloak-hawtio.json | 9 + .../app-server/jboss/eap6-fuse/pom.xml | 132 ++++++++ .../jboss/eap6-fuse/src/adapter-supported | 0 .../servers/app-server/jboss/pom.xml | 12 +- .../testsuite/adapter/page/HawtioPage.java | 24 ++ .../arquillian/provider/URLProvider.java | 2 +- .../page/AbstractPageWithInjectedUrl.java | 2 +- .../adapter/AbstractAdapterTest.java | 1 + .../example/AbstractHawtioAdapterTest.java | 41 +++ .../adapter-test/hawtio-realm/demorealm.json | 285 ++++++++++++++++++ .../other/adapters/jboss/eap6-fuse/pom.xml | 41 +++ .../example/EAP6FUSEHawtioAdapterTest.java | 10 + .../tests/other/adapters/jboss/pom.xml | 9 +- .../tests/other/adapters/pom.xml | 6 + 17 files changed, 626 insertions(+), 7 deletions(-) create mode 100644 testsuite/integration-arquillian/servers/app-server/jboss/common/add-hawtio.xsl create mode 100755 testsuite/integration-arquillian/servers/app-server/jboss/common/install-fuse.sh create mode 100644 testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio-client.json create mode 100644 testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio.json create mode 100644 testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/pom.xml create mode 100644 testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/src/adapter-supported create mode 100644 testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/HawtioPage.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractHawtioAdapterTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/hawtio-realm/demorealm.json create mode 100644 testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml create mode 100644 testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/src/test/java/org/keycloak/testsuite/adapter/example/EAP6FUSEHawtioAdapterTest.java diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/add-hawtio.xsl b/testsuite/integration-arquillian/servers/app-server/jboss/common/add-hawtio.xsl new file mode 100644 index 0000000000..cf158c0003 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/add-hawtio.xsl @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/install-fuse.sh b/testsuite/integration-arquillian/servers/app-server/jboss/common/install-fuse.sh new file mode 100755 index 0000000000..c82821c112 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/install-fuse.sh @@ -0,0 +1,12 @@ +#!/bin/bash +echo "FUSE_INSTALLER=$JBOSS_HOME/$FUSE_INSTALLER_NAME" +if [ ! -f "$JBOSS_HOME/$FUSE_INSTALLER_NAME" ] ; then + >&2 echo "JBOSS_HOME/$FUSE_INSTALLER_NAME doesn't exist" + exit 1 +fi + +cd $JBOSS_HOME +java -jar $FUSE_INSTALLER_NAME +rm $FUSE_INSTALLER_NAME + +exit 0 \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio-client.json b/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio-client.json new file mode 100644 index 0000000000..c84b54be86 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio-client.json @@ -0,0 +1,7 @@ +{ + "realm" : "demo", + "resource" : "hawtio-client", + "auth-server-url" : "http://localhost:8180/auth", + "ssl-required" : "external", + "public-client" : true +} diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio.json b/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio.json new file mode 100644 index 0000000000..71b1700905 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/keycloak-hawtio.json @@ -0,0 +1,9 @@ +{ + "realm" : "demo", + "resource" : "jaas", + "bearer-only" : true, + "auth-server-url" : "http://localhost:8180/auth", + "ssl-required" : "external", + "use-resource-role-mappings": false, + "principal-attribute": "preferred_username" +} diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/pom.xml new file mode 100644 index 0000000000..1f7c62a72f --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/pom.xml @@ -0,0 +1,132 @@ + + + + integration-arquillian-servers-app-server-jboss + org.keycloak.testsuite + 2.4.0.CR1-SNAPSHOT + + 4.0.0 + + integration-arquillian-servers-app-server-eap6-fuse + pom + App Server - JBoss - EAP 6 + Fuse integration + + + eap6-fuse + + org.jboss.as + jboss-as-dist + ${eap6.version} + jboss-eap-6.4 + + com.redhat.fuse.eap + fuse-eap-installer + 6.3.0.redhat-187 + + keycloak-eap6-adapter-dist + + + + + + maven-dependency-plugin + + + unpack-fuse-installer + generate-resources + + copy + + + + + ${fuse.installer.groupId} + ${fuse.installer.artifactId} + ${fuse.installer.version} + jar + ${app.server.jboss.home} + + + + + + + + org.codehaus.mojo + exec-maven-plugin + + + install-fuse + process-resources + + exec + + + ${common.resources}/install-fuse.${script.suffix} + ${app.server.jboss.home} + + ${app.server.java.home} + ${app.server.jboss.home} + ${fuse.installer.artifactId}-${fuse.installer.version}.jar + + + + + + + maven-resources-plugin + 3.0.1 + + + copy-hawtio-jsons + process-test-resources + + copy-resources + + + ${app.server.jboss.home}/standalone/configuration + + + ${common.resources} + + keycloak-hawtio.json + keycloak-hawtio-client.json + + true + + + + + + + + + org.codehaus.mojo + xml-maven-plugin + + + add-hawtio-to-standalone + process-test-resources + + transform + + + + + ${app.server.jboss.home}/standalone/configuration + + standalone.xml + + ${common.resources}/add-hawtio.xsl + ${app.server.jboss.home}/standalone/configuration + + + + + + + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/src/adapter-supported b/testsuite/integration-arquillian/servers/app-server/jboss/eap6-fuse/src/adapter-supported new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml index 8cd3f30281..4f7c1238bd 100644 --- a/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml +++ b/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml @@ -108,7 +108,7 @@ configure-adapter-debug-log - process-resources + process-test-resources transform @@ -189,7 +189,7 @@ install-adapters - process-test-resources + process-resources exec @@ -437,7 +437,13 @@ relative - + + + app-server-eap6-fuse + + eap6-fuse + + diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/HawtioPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/HawtioPage.java new file mode 100644 index 0000000000..66a2434415 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/HawtioPage.java @@ -0,0 +1,24 @@ +package org.keycloak.testsuite.adapter.page; + +import org.keycloak.testsuite.page.AbstractPage; + +import javax.ws.rs.core.UriBuilder; +import java.net.URL; + +/** + * @author mhajas + */ +public class HawtioPage extends AbstractPage { + + public String getUrl() { + if (Boolean.parseBoolean(System.getProperty("app.server.ssl.required"))) { + return "https://localhost:" + System.getProperty("app.server.https.port", "8543") + "/hawtio"; + } + return "http://localhost:" + System.getProperty("app.server.http.port", "8180") + "/hawtio"; + } + + @Override + public UriBuilder createUriBuilder() { + return UriBuilder.fromUri(getUrl()); + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java index 5631b6a03e..77640aada5 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java @@ -74,7 +74,7 @@ public class URLProvider extends URLResourceProvider { } try { - if ("eap6".equals(System.getProperty("app.server"))) { + if (System.getProperty("app.server","").startsWith("eap6")) { if (url == null) { url = new URL("http://localhost:8080/"); } diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java index e678db4341..b86dac1c9c 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPageWithInjectedUrl.java @@ -32,7 +32,7 @@ public abstract class AbstractPageWithInjectedUrl extends AbstractPage { //EAP6 URL fix protected URL createInjectedURL(String url) { - if (!System.getProperty("app.server").equals("eap6")) { + if (!System.getProperty("app.server","").startsWith("eap6")) { return null; } try { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java index a42234c565..5f221ad46e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractAdapterTest.java @@ -68,6 +68,7 @@ public abstract class AbstractAdapterTest extends AbstractAuthTest { } else { modifyClientRedirectUris(tr, "^(/.*/\\*)", appServerContextRootPage.toString() + "$1"); modifyClientUrls(tr, "^(/.*)", appServerContextRootPage.toString() + "$1"); + modifyClientWebOrigins(tr, "8080", System.getProperty("app.server.http.port", null)); modifySamlMasterURLs(tr, "8080", System.getProperty("auth.server.http.port", null)); modifySAMLClientsAttributes(tr, "8080", System.getProperty("app.server.http.port", "8280")); modifyClientJWKSUrl(tr, "^(/.*)", appServerContextRootPage.toString() + "$1"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractHawtioAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractHawtioAdapterTest.java new file mode 100644 index 0000000000..d5e1da1089 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractHawtioAdapterTest.java @@ -0,0 +1,41 @@ +package org.keycloak.testsuite.adapter.example; + +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Ignore; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest; +import org.keycloak.testsuite.adapter.page.HawtioPage; + +import java.io.File; +import java.util.List; + +import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO; +import static org.keycloak.testsuite.util.IOUtil.loadRealm; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; + +/** + * @author mhajas + */ +public class AbstractHawtioAdapterTest extends AbstractExampleAdapterTest { + + @Page + private HawtioPage hawtioPage; + + @Override + public void addAdapterTestRealms(List testRealms) { + testRealms.add(loadRealm("/adapter-test/hawtio-realm/demorealm.json")); + } + + @Test + @Ignore //Waiting for PATCH-1446 + public void hawtioTest() { + testRealmLoginPage.setAuthRealm(DEMO); + hawtioPage.navigateTo(); + assertCurrentUrlStartsWith(testRealmLoginPage); + testRealmLoginPage.form().login("root", "password"); + + assertCurrentUrlStartsWith(hawtioPage.getDriver(), hawtioPage.toString() + "/welcome"); + + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/hawtio-realm/demorealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/hawtio-realm/demorealm.json new file mode 100644 index 0000000000..fe410adb4c --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/hawtio-realm/demorealm.json @@ -0,0 +1,285 @@ +{ + "realm": "demo", + "enabled": true, + "accessTokenLifespan": 60, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "ssoSessionIdleTimeout": 600, + "ssoSessionMaxLifespan": 36000, + "sslRequired": "external", + "registrationAllowed": false, + "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=", + "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", + "requiredCredentials": [ "password" ], + "users" : [ + { + "username" : "bburke@redhat.com", + "enabled": true, + "email" : "bburke@redhat.com", + "firstName": "Bill", + "lastName": "Burke", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": [ "user" ], + "clientRoles": { + "account": [ "manage-account" ] + } + }, + { + "username" : "stian", + "enabled": true, + "email" : "stian@redhat.com", + "firstName": "Stian", + "lastName": "Thorgersen", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": [ "user" ], + "clientRoles": { + "account": [ "manage-account" ] + } + }, + { + "username" : "mposolda@redhat.com", + "enabled": true, + "email" : "mposolda@redhat.com", + "firstName": "Marek", + "lastName": "Posolda", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": [ "user" ], + "clientRoles": { + "account": [ "manage-account" ] + } + }, + { + "username" : "admin", + "enabled": true, + "email" : "admin@admin.com", + "firstName": "Admin", + "lastName": "Burke", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": [ "user","admin" ], + "clientRoles": { + "realm-management": [ "realm-admin" ], + "account": [ "manage-account" ] + } + }, + { + "username" : "jmxadmin", + "enabled": true, + "email" : "jmxadmin@admin.com", + "firstName": "JmxAdmin", + "lastName": "Burke", + "credentials" : [ + { "type" : "password", + "value" : "password" } + ], + "realmRoles": [ "user", "jmxAdmin" ], + "clientRoles": { + "account": [ "manage-account" ], + "realm-management": [ "realm-admin" ] + } + }, + { + "username" : "john", + "firstName" : "John", + "lastName" : "Anthony", + "email" : "john@hawt.io", + "enabled" : true, + "credentials" : [ + { + "type" : "password", + "value" : "password" + } + ], + "realmRoles" : [ "viewer" ], + "applicationRoles": { + "account" : [ "view-profile", "manage-account" ] + } + }, + { + "username" : "mary", + "firstName" : "Mary", + "lastName" : "Kelly", + "email" : "mary@hawt.io", + "enabled" : true, + "credentials" : [ + { + "type" : "password", + "value" : "password" + } + ], + "applicationRoles": { + "account" : [ "view-profile", "manage-account" ] + } + }, + { + "username" : "root", + "firstName" : "Root", + "lastName" : "Root", + "email" : "root@hawt.io", + "enabled" : true, + "credentials" : [ + { + "type" : "password", + "value" : "password" + } + ], + "realmRoles" : [ "jmxAdmin" ], + "applicationRoles": { + "account" : [ "view-profile", "manage-account" ], + "realm-management" : [ "realm-admin" ] + } + } + ], + "roles" : { + "realm" : [ + { + "name": "user", + "description": "User privileges" + }, + { + "name": "admin", + "description": "Administrator privileges" + }, + { + "name": "manager" + }, + { + "name": "viewer" + }, + { + "name": "Operator" + }, + { + "name": "Maintainer" + }, + { + "name": "Deployer" + }, + { + "name": "Auditor" + }, + { + "name": "Administrator" + }, + { + "name": "SuperUser" + }, + { + "name": "jmxAdmin", + "description": "Admin role with all privileges to SSH and JMX access", + "composite": true, + "composites": { + "realm": [ "admin", "manager", "viewer", "Operator", "Maintainer", "Deployer", "Auditor", "Administrator", "SuperUser" ] + } + } + ] + }, + "clients": [ + { + "clientId": "customer-portal", + "enabled": true, + "adminUrl": "http://localhost:8181/customer-portal", + "baseUrl": "http://localhost:8181/customer-portal", + "redirectUris": [ + "http://localhost:8181/customer-portal/*" + ], + "secret": "password" + }, + { + "clientId": "example-camel-cdi", + "enabled": true, + "adminUrl": "http://localhost:8080/example-camel-cdi", + "baseUrl": "http://localhost:8080/example-camel-cdi", + "redirectUris": [ + "http://localhost:8080/example-camel-cdi/*" + ], + "secret": "password" + }, + { + "clientId": "product-portal", + "enabled": true, + "adminUrl": "http://localhost:8181/product-portal", + "baseUrl": "http://localhost:8181/product-portal", + "redirectUris": [ + "http://localhost:8181/product-portal/*" + ], + "secret": "password" + }, + { + "clientId": "builtin-cxf-app", + "enabled": true, + "adminUrl": "http://localhost:8181/cxf", + "baseUrl": "http://localhost:8181/cxf", + "redirectUris": [ + "http://localhost:8181/cxf/*" + ], + "secret": "password" + }, + { + "clientId": "custom-cxf-endpoint", + "enabled": true, + "adminUrl": "http://localhost:8282/PersonServiceCF", + "baseUrl": "http://localhost:8282/PersonServiceCF", + "bearerOnly": true + }, + { + "clientId": "admin-camel-endpoint", + "enabled": true, + "adminUrl": "http://localhost:8383/admin-camel-endpoint", + "baseUrl": "http://localhost:8383/admin-camel-endpoint", + "bearerOnly": true + }, + { + "clientId": "ssh-jmx-admin-client", + "enabled": true, + "publicClient": false, + "standardFlowEnabled": false, + "directAccessGrantsEnabled": true, + "secret": "password" + }, + { + "clientId": "external-config", + "enabled": true, + "adminUrl": "http://localhost:8181/external-config", + "baseUrl": "http://localhost:8181/external-config", + "redirectUris": [ + "http://localhost:8181/external-config", + "http://localhost:8181/external-config/*" + ], + "secret": "password" + }, + { + "clientId" : "hawtio-client", + "surrogateAuthRequired" : false, + "fullScopeAllowed" : false, + "enabled" : true, + "redirectUris" : ["http://localhost:8080/hawtio/*" ], + "webOrigins" : [ "http://localhost:8080"], + "bearerOnly" : false, + "publicClient" : true, + "protocol" : "openid-connect" + } + + ], + "scopeMappings": [ + { + "client": "ssh-jmx-admin-client", + "roles": [ "admin", "jmxAdmin" ] + }, + { + "client": "hawtio-client", + "roles": [ "viewer", "jmxAdmin" ] + } + ] +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml new file mode 100644 index 0000000000..426884f250 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/pom.xml @@ -0,0 +1,41 @@ + + + + + + 4.0.0 + + + org.keycloak.testsuite + integration-arquillian-tests-adapters-jboss + 2.4.0.CR1-SNAPSHOT + + + integration-arquillian-tests-adapters-eap6-fuse + + Adapter Tests - JBoss - EAP 6 + + + eap6-fuse + + remote + ${app.server.management.port.jmx} + + + \ No newline at end of file diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/src/test/java/org/keycloak/testsuite/adapter/example/EAP6FUSEHawtioAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/src/test/java/org/keycloak/testsuite/adapter/example/EAP6FUSEHawtioAdapterTest.java new file mode 100644 index 0000000000..ab23db94dd --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6-fuse/src/test/java/org/keycloak/testsuite/adapter/example/EAP6FUSEHawtioAdapterTest.java @@ -0,0 +1,10 @@ +package org.keycloak.testsuite.adapter.example; + +import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; + +/** + * @author mhajas + */ +@AppServerContainer("app-server-eap6-fuse") +public class EAP6FUSEHawtioAdapterTest extends AbstractHawtioAdapterTest { +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml index 48cce66d2d..d7ce8e923a 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml @@ -176,8 +176,13 @@ relative - - + + + app-server-eap6-fuse + + eap6-fuse + + diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml index b99ccc16d3..07f7c2506b 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml @@ -332,6 +332,12 @@ ${project.version} war + + org.keycloak.testsuite + integration-arquillian-test-apps-example-camel-cdi + ${project.version} + war + ${examples.home} true From 782620655f073f2b8cef85b42cfd0e7e152080cf Mon Sep 17 00:00:00 2001 From: mhajas Date: Tue, 1 Nov 2016 11:09:43 +0100 Subject: [PATCH 08/21] KEYCLOAK-3142 Check ResourceType in AdminEvent test --- .../org/keycloak/testsuite/console/events/AdminEventsTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java index a5a937ae25..5398fc58ee 100644 --- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java +++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/AdminEventsTest.java @@ -88,6 +88,7 @@ public class AdminEventsTest extends AbstractConsoleTest { assertEquals(1, resultList.size()); resultList.get(0).findElement(By.xpath("//td[text()='CREATE']")); resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']")); + resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']")); adminEventsPage.table().reset(); adminEventsPage.table().filterForm().addOperationType("UPDATE"); @@ -97,6 +98,7 @@ public class AdminEventsTest extends AbstractConsoleTest { assertEquals(1, resultList.size()); resultList.get(0).findElement(By.xpath("//td[text()='UPDATE']")); resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']")); + resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']")); adminEventsPage.table().reset(); adminEventsPage.table().filterForm().addOperationType("DELETE"); @@ -106,6 +108,7 @@ public class AdminEventsTest extends AbstractConsoleTest { assertEquals(1, resultList.size()); resultList.get(0).findElement(By.xpath("//td[text()='DELETE']")); resultList.get(0).findElement(By.xpath("//td[text()='clients/" + id + "']")); + resultList.get(0).findElement(By.xpath("//td[text()='CLIENT']")); } public ClientsResource clientsResource() { From fdb7924d3f1948726ba479551b81829d09cfe40f Mon Sep 17 00:00:00 2001 From: Vlasta Ramik Date: Tue, 1 Nov 2016 11:31:19 +0100 Subject: [PATCH 09/21] add test for KEYCLOAK-2957 to arquillian testsuite --- .../testsuite/broker/AbstractBrokerTest.java | 72 +++++++++++++++++++ .../keycloak/testsuite/util/MailAssert.java | 3 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java index 0b568b8e95..e6e0aeb8e4 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java @@ -28,8 +28,15 @@ import java.net.URLEncoder; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient; import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword; +import static org.keycloak.testsuite.broker.BrokerTestConstants.USER_EMAIL; +import org.keycloak.testsuite.pages.IdpConfirmLinkPage; +import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl; +import org.keycloak.testsuite.util.MailServer; +import org.keycloak.testsuite.util.MailServerConfiguration; +import org.keycloak.testsuite.util.UserBuilder; public abstract class AbstractBrokerTest extends AbstractKeycloakTest { @@ -61,6 +68,9 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest { @Page protected ErrorPage errorPage; + + @Page + protected IdpConfirmLinkPage idpConfirmLinkPage; @Override public void addTestRealms(List testRealms) { @@ -199,6 +209,68 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest { assertEquals(userCount, adminClient.realm(consumerRealmName()).users().count()); } + + // KEYCLOAK-2957 + @Test + public void testLinkAccountWithEmailVerified() { + //start mail server + MailServer.start(); + MailServer.createEmailAccount(USER_EMAIL, "password"); + + try { + //configure smpt server in the realm + RealmRepresentation master = adminClient.realm(consumerRealmName()).toRepresentation(); + master.setSmtpServer(suiteContext.getSmtpServer()); + adminClient.realm(consumerRealmName()).update(master); + + //create user on consumer's site who should be linked later + UserRepresentation newUser = UserBuilder.create().username("consumer").email(USER_EMAIL).enabled(true).build(); + String userId = createUserWithAdminClient(adminClient.realm(consumerRealmName()), newUser); + resetUserPassword(adminClient.realm(consumerRealmName()).users().get(userId), "password", false); + + //test + driver.navigate().to(getAccountUrl(consumerRealmName())); + + log.debug("Clicking social " + getIDPAlias()); + accountLoginPage.clickSocial(getIDPAlias()); + + waitForPage("log in to"); + + Assert.assertTrue("Driver should be on the provider realm page right now", + driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/")); + + log.debug("Logging in"); + accountLoginPage.login(getUserLogin(), getUserPassword()); + + waitForPage("update account information"); + + Assert.assertTrue(updateAccountInformationPage.isCurrent()); + Assert.assertTrue("We must be on correct realm right now", + driver.getCurrentUrl().contains("/auth/realms/" + consumerRealmName() + "/")); + + log.debug("Updating info on updateAccount page"); + updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname"); + + //link account by email + waitForPage("account already exists"); + idpConfirmLinkPage.clickLinkAccount(); + + String url = assertEmailAndGetUrl(MailServerConfiguration.FROM, USER_EMAIL, + "Someone wants to link your ", false); + + log.info("navigating to url from email: " + url); + driver.navigate().to(url); + + //test if user is logged in + assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl()); + + //test if the user has verified email + assertTrue(adminClient.realm(consumerRealmName()).users().get(userId).toRepresentation().isEmailVerified()); + } finally { + // stop mail server + MailServer.stop(); + } + } // KEYCLOAK-3267 @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java index 5d3099b6a5..463c32fa85 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java @@ -41,7 +41,8 @@ public class MailAssert { message= SslMailServer.getLastReceivedMessage(); } else { message = MailServer.getLastReceivedMessage(); - } assertNotNull("There is no received email.", message); + } + assertNotNull("There is no received email.", message); assertEquals(recipient, message.getRecipients(RecipientType.TO)[0].toString()); assertEquals(from, message.getFrom()[0].toString()); From cef1973ee4331bef1adc488db035b1e3a87c23fc Mon Sep 17 00:00:00 2001 From: Vlasta Ramik Date: Wed, 2 Nov 2016 13:46:53 +0100 Subject: [PATCH 10/21] KEYCLOAK-3579 add preview profile assumption to tests --- .../java/org/keycloak/testsuite/admin/PermissionsTest.java | 2 ++ .../keycloak/testsuite/exportimport/ExportImportUtil.java | 7 +++++-- .../test/java/org/keycloak/testsuite/i18n/EmailTest.java | 5 +++-- .../java/org/keycloak/testsuite/i18n/LoginPageTest.java | 4 +++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java index 29252d98d4..7d005e95dd 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java @@ -78,6 +78,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.keycloak.services.resources.admin.RealmAuth.Resource.AUTHORIZATION; import static org.keycloak.services.resources.admin.RealmAuth.Resource.CLIENT; +import org.keycloak.testsuite.ProfileAssume; /** * @author Stian Thorgersen @@ -782,6 +783,7 @@ public class PermissionsTest extends AbstractKeycloakTest { @Test public void clientAuthorization() { + ProfileAssume.assumePreview(); invoke(new InvocationWithResponse() { public void invoke(RealmResource realm, AtomicReference response) { realm.clients().create(ClientBuilder.create().clientId("foo-authz").build()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java index 386b291659..2c45818773 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java @@ -61,6 +61,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; +import org.keycloak.common.Profile; /** * @@ -374,8 +375,10 @@ public class ExportImportUtil { UserRepresentation linked = testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), otherApp.getClientId());//session.users().getUserByServiceAccountClient(otherApp); Assert.assertNotNull(linked); Assert.assertEquals("my-service-user", linked.getUsername()); - - assertAuthorizationSettings(realmRsc); + + if (Profile.isPreviewEnabled()) { + assertAuthorizationSettings(realmRsc); + } } private static boolean isProtocolMapperGranted(Map consent, ProtocolMapperRepresentation mapperRep) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java index 42f85e6e70..163f60209f 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/EmailTest.java @@ -30,10 +30,9 @@ import org.keycloak.testsuite.util.GreenMailRule; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; import static org.junit.Assert.assertEquals; +import org.keycloak.testsuite.ProfileAssume; /** * @author Michael Gerber @@ -84,6 +83,8 @@ public class EmailTest extends AbstractI18NTest { @Test public void restPasswordEmailGerman() throws IOException, MessagingException { + ProfileAssume.assumePreview(); + changeUserLocale("de"); loginPage.open(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java index 4a0da21ecf..3bc1a0231d 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java @@ -17,7 +17,6 @@ package org.keycloak.testsuite.i18n; import org.apache.http.impl.client.DefaultHttpClient; -import org.jboss.arquillian.graphene.page.Page; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine; @@ -29,6 +28,7 @@ import org.keycloak.testsuite.pages.LoginPage; import javax.ws.rs.core.Response; import org.jboss.arquillian.graphene.page.Page; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.util.IdentityProviderBuilder; /** @@ -97,6 +97,8 @@ public class LoginPageTest extends AbstractI18NTest { @Test public void acceptLanguageHeader() { + ProfileAssume.assumePreview(); + DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build(); ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient); ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build(); From d7c5f991c808bc9e9cd6e259923f81a64f33985f Mon Sep 17 00:00:00 2001 From: Tomas Kyjovsky Date: Wed, 2 Nov 2016 15:51:06 +0100 Subject: [PATCH 11/21] KEYCLOAK-3579: added ability to select keycloak.profile in testsuite --- .../base/src/test/resources/arquillian.xml | 3 +++ testsuite/integration-arquillian/tests/pom.xml | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml index 5aea8bee6e..8dc077d3ea 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml +++ b/testsuite/integration-arquillian/tests/base/src/test/resources/arquillian.xml @@ -67,6 +67,7 @@ -Djboss.bind.address=0.0.0.0 ${adapter.test.props} ${migration.import.properties} + ${auth.server.profile} ${auth.server.memory.settings} @@ -89,6 +90,7 @@ -Djboss.socket.binding.port-offset=${auth.server.backend1.port.offset} -Djboss.node.name=node1 ${adapter.test.props} + ${auth.server.profile} ${auth.server.memory.settings} @@ -109,6 +111,7 @@ -Djboss.socket.binding.port-offset=${auth.server.backend2.port.offset} -Djboss.node.name=node2 ${adapter.test.props} + ${auth.server.profile} ${auth.server.memory.settings} diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 4f8e9348c9..ea63ca4bb1 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -61,8 +61,9 @@ integration-arquillian-servers-auth-server-${auth.server} ${auth.server.undertow} 300 - + false + @@ -163,6 +164,8 @@ ${auth.server.config.property.value} ${auth.server.adapter.impl.class} + ${auth.server.profile} + ${frontend.console.output} ${backend.console.output} @@ -246,6 +249,18 @@ + + auth-server-profile + + + keycloak.profile + + + + -Dkeycloak.profile=${keycloak.profile} + + + auth-server-cluster From c5b6507830472f3015a99c0a89674198cd2af856 Mon Sep 17 00:00:00 2001 From: mhajas Date: Wed, 2 Nov 2016 14:42:23 +0100 Subject: [PATCH 12/21] KEYCLOAK-3850 Fix test-apps-dist zip file name --- .../test-apps/test-apps-dist/pom.xml | 2 +- .../testsuite/adapter/AbstractExampleAdapterTest.java | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml b/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml index 7e8fd955bb..8ebed0c5c6 100644 --- a/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml +++ b/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml @@ -14,7 +14,7 @@ Test apps distribution - ${product.name}-${product.version}-test-apps + test-apps-dist org.apache.maven.plugins diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java index 065477a407..4521162588 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractExampleAdapterTest.java @@ -51,13 +51,7 @@ public abstract class AbstractExampleAdapterTest extends AbstractAdapterTest { System.out.println(EXAMPLES_VERSION_SUFFIX); EXAMPLES_HOME_DIR = EXAMPLES_HOME + "/example-realms"; - - if (!System.getProperty("unpacked.container.folder.name","").isEmpty()) { - TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/" + System.getProperty("unpacked.container.folder.name","") + "-test-apps"; - } else { - TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/Keycloak-" + EXAMPLES_VERSION_SUFFIX + "-test-apps"; - } - + TEST_APPS_HOME_DIR = EXAMPLES_HOME + "/test-apps-dist"; EXAMPLES_WEB_XML = EXAMPLES_HOME + "/web.xml"; } From ad995934b0811385febe3f1bf37727819fc7464c Mon Sep 17 00:00:00 2001 From: mhajas Date: Wed, 2 Nov 2016 11:43:56 +0100 Subject: [PATCH 13/21] KEYCLOAK-3728 Test for turned off script based authenticators --- .../admin/authentication/ProvidersTest.java | 6 +++- .../ScriptBasedAuthenticatorTest.java | 31 +++++++++++++++++++ .../forms/ScriptAuthenticatorTest.java | 9 +++--- 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ScriptBasedAuthenticatorTest.java diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java index c46a620b61..e226d5016f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java @@ -32,6 +32,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import static org.keycloak.common.Profile.isPreviewEnabled; + /** * @author Marko Strukelj */ @@ -135,7 +137,9 @@ public class ProvidersTest extends AbstractAuthenticationTest { "Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions."); addProviderInfo(result, "auth-cookie", "Cookie", "Validates the SSO cookie set by the auth server."); addProviderInfo(result, "auth-otp-form", "OTP Form", "Validates a OTP on a separate OTP form."); - addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript."); + if (isPreviewEnabled()) { + addProviderInfo(result, "auth-script-based", "Script", "Script based authentication. Allows to define custom authentication logic via JavaScript."); + } addProviderInfo(result, "auth-spnego", "Kerberos", "Initiates the SPNEGO protocol. Most often used with Kerberos."); addProviderInfo(result, "auth-username-password-form", "Username Password Form", "Validates a username and password from login form."); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ScriptBasedAuthenticatorTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ScriptBasedAuthenticatorTest.java new file mode 100644 index 0000000000..3466928a90 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ScriptBasedAuthenticatorTest.java @@ -0,0 +1,31 @@ +package org.keycloak.testsuite.admin.authentication; + +import org.junit.Assert; +import org.junit.Test; +import org.keycloak.testsuite.ProfileAssume; + +import javax.ws.rs.BadRequestException; +import java.util.HashMap; + +/** + * @author mhajas + */ +public class ScriptBasedAuthenticatorTest extends AbstractAuthenticationTest { + + @Test + public void checkIfTurnedOffWithProductProfile() throws InterruptedException { + ProfileAssume.assumePreviewDisabled(); + + HashMap params = new HashMap<>(); + params.put("newName", "Copy-of-browser"); + authMgmtResource.copy("browser", params); + + params.put("provider", "auth-script-based"); + try { + authMgmtResource.addExecution("Copy-of-browser", params); + Assert.fail("Adding script based authenticator should fail with product profile"); + } catch (BadRequestException ex) { + //Expected + } + } +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ScriptAuthenticatorTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ScriptAuthenticatorTest.java index 61cc47c94b..34113d811c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ScriptAuthenticatorTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ScriptAuthenticatorTest.java @@ -18,10 +18,7 @@ package org.keycloak.testsuite.forms; import org.apache.commons.io.IOUtils; import org.jboss.arquillian.graphene.page.Page; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory; import org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory; import org.keycloak.events.Details; @@ -34,6 +31,7 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testsuite.AssertEvents; +import org.keycloak.testsuite.ProfileAssume; import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.util.ExecutionBuilder; import org.keycloak.testsuite.util.FlowBuilder; @@ -62,6 +60,9 @@ public class ScriptAuthenticatorTest extends AbstractFlowTest { private AuthenticationFlowRepresentation flow; + @BeforeClass + public static void enabled() { ProfileAssume.assumePreview(); } + @Override public void configureTestRealm(RealmRepresentation testRealm) { From ae2a1e929fe086a1bb1d232b7a22048e08dcf5f0 Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Wed, 2 Nov 2016 13:53:15 -0400 Subject: [PATCH 14/21] KEYCLOAK-3816: Broken OTP setup with smaller resolutions --- .../theme/keycloak/login/resources/css/login.css | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css index 0ed51ac51d..54eb79655c 100644 --- a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css +++ b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css @@ -244,18 +244,26 @@ ol#kc-totp-settings li:first-of-type { .zocial.microsoft {background-color: #0052a4; color: #fff;} .zocial.microsoft:before { content: "\f15d"; } +@media (min-width: 801px) { + #kc-container-wrapper { + bottom: 13%; + } + + #kc-logo-wrapper { + position: absolute; + top: 50px; + right: 50px; + } +} @media (min-width: 768px) { #kc-container-wrapper { - bottom: 13%; position: absolute; width: 100%; } #kc-logo-wrapper { - position: absolute; - top: 50px; - right: 50px; + margin-left: auto; } .login-pf .container { From a315919dfc3953f120199a8d7878a043ad4005a9 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 2 Nov 2016 18:11:30 -0200 Subject: [PATCH 15/21] [KEYCLOAK-3555] - Filtering photoz authz config file to update project version. --- examples/authz/photoz/README.md | 4 +++- examples/authz/photoz/photoz-restful-api/pom.xml | 6 ++++++ .../main/resources}/photoz-restful-api-authz-service.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) rename examples/authz/photoz/{ => photoz-restful-api/src/main/resources}/photoz-restful-api-authz-service.json (99%) diff --git a/examples/authz/photoz/README.md b/examples/authz/photoz/README.md index c915a1ffc9..8ae6b7c95f 100644 --- a/examples/authz/photoz/README.md +++ b/examples/authz/photoz/README.md @@ -63,6 +63,8 @@ JBoss Drools, which require ``photoz-authz-policy`` artifact installed into your cd examples/authz/photoz mvn clean install + +> Please make sure you have the environment variable M2_HOME set. It should reference the path for your Maven installation. If not set, you will see some WARN messages in the logs when booting Keycloak. Now, let's import another configuration using the Administration Console in order to configure the client application ``photoz-restful-api`` as a resource server with all resources, scopes, permissions and policies. @@ -71,7 +73,7 @@ open the ``Client Details`` page. Once there, click on the `Authorization` tab. Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at: - examples/authz/photoz/photoz-restful-api/photoz-restful-api-authz-config.json + examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json Now click ``Upload`` and the resource server will be updated accordingly. diff --git a/examples/authz/photoz/photoz-restful-api/pom.xml b/examples/authz/photoz/photoz-restful-api/pom.xml index 0059ae93dc..84665a215f 100755 --- a/examples/authz/photoz/photoz-restful-api/pom.xml +++ b/examples/authz/photoz/photoz-restful-api/pom.xml @@ -55,6 +55,12 @@ ${project.artifactId} + + + src/main/resources + true + + org.jboss.as.plugins diff --git a/examples/authz/photoz/photoz-restful-api-authz-service.json b/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json similarity index 99% rename from examples/authz/photoz/photoz-restful-api-authz-service.json rename to examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json index 455948c493..a87aa0a445 100644 --- a/examples/authz/photoz/photoz-restful-api-authz-service.json +++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/photoz-restful-api-authz-service.json @@ -47,7 +47,7 @@ "logic": "POSITIVE", "decisionStrategy": "UNANIMOUS", "config": { - "mavenArtifactVersion": "2.1.0-SNAPSHOT", + "mavenArtifactVersion": "${project.version}", "mavenArtifactId": "photoz-authz-policy", "sessionName": "MainOwnerSession", "mavenArtifactGroupId": "org.keycloak", From 95d2130405c938e62a59864f4ee6740a493b08c3 Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 2 Nov 2016 21:01:24 -0200 Subject: [PATCH 16/21] [KEYCLOAK-3704] - Checkign if owner is a valid user --- .../admin/ResourceSetService.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java index 9389992316..8db12f8a97 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java @@ -28,8 +28,11 @@ import org.keycloak.authorization.store.ResourceStore; import org.keycloak.authorization.store.StoreFactory; import org.keycloak.models.ClientModel; import org.keycloak.models.Constants; +import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.models.UserFederationManager; import org.keycloak.models.UserModel; +import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.services.ErrorResponse; import org.keycloak.services.resources.admin.RealmAuth; @@ -76,12 +79,28 @@ public class ResourceSetService { requireManage(); StoreFactory storeFactory = this.authorization.getStoreFactory(); Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId()); + ResourceOwnerRepresentation owner = resource.getOwner(); if (existingResource != null && existingResource.getResourceServer().getId().equals(this.resourceServer.getId()) - && existingResource.getOwner().equals(resource.getOwner())) { + && existingResource.getOwner().equals(owner)) { return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists."); } + String ownerId = owner.getId(); + + if (ownerId != null) { + if (!resourceServer.getClientId().equals(ownerId)) { + RealmModel realm = authorization.getRealm(); + KeycloakSession keycloakSession = authorization.getKeycloakSession(); + UserFederationManager users = keycloakSession.users(); + UserModel ownerModel = users.getUserByUsername(ownerId, realm); + + if (ownerModel == null) { + return ErrorResponse.error("Owner must be a valid username or, if the resource server, the client id.", Status.BAD_REQUEST); + } + } + } + Resource model = toModel(resource, this.resourceServer, authorization); ResourceRepresentation representation = new ResourceRepresentation(); From 706c1e2660a9a7eec442c34050db9f38aeba79eb Mon Sep 17 00:00:00 2001 From: Pedro Igor Date: Wed, 2 Nov 2016 21:40:58 -0200 Subject: [PATCH 17/21] [KEYCLOAK-3704] - Registering UserSinchronizer to remove resources when the owner is removed --- .../store/AuthorizationStoreFactory.java | 3 + .../syncronization/UserSynchronizer.java | 55 +++++++++++++++++++ .../admin/ResourceSetService.java | 28 ++++++---- 3 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java index 6179cc7288..78a08bd42a 100644 --- a/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java +++ b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java @@ -21,9 +21,11 @@ package org.keycloak.authorization.store; import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer; import org.keycloak.authorization.store.syncronization.RealmSynchronizer; import org.keycloak.authorization.store.syncronization.Synchronizer; +import org.keycloak.authorization.store.syncronization.UserSynchronizer; import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.RealmModel.ClientRemovedEvent; import org.keycloak.models.RealmModel.RealmRemovedEvent; +import org.keycloak.models.UserModel.UserRemovedEvent; import org.keycloak.provider.ProviderEvent; import org.keycloak.provider.ProviderFactory; @@ -45,6 +47,7 @@ public interface AuthorizationStoreFactory extends ProviderFactory synchronizers.put(ClientRemovedEvent.class, new ClientApplicationSynchronizer()); synchronizers.put(RealmRemovedEvent.class, new RealmSynchronizer()); + synchronizers.put(UserRemovedEvent.class, new UserSynchronizer()); factory.register(event -> { try { diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java new file mode 100644 index 0000000000..01830ff07a --- /dev/null +++ b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/UserSynchronizer.java @@ -0,0 +1,55 @@ +/* + * 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.authorization.store.syncronization; + +import org.keycloak.authorization.AuthorizationProvider; +import org.keycloak.authorization.store.PolicyStore; +import org.keycloak.authorization.store.ResourceStore; +import org.keycloak.authorization.store.StoreFactory; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserModel.UserRemovedEvent; +import org.keycloak.provider.ProviderFactory; + +/** + * @author Pedro Igor + */ +public class UserSynchronizer implements Synchronizer { + + @Override + public void synchronize(UserRemovedEvent event, KeycloakSessionFactory factory) { + ProviderFactory providerFactory = factory.getProviderFactory(AuthorizationProvider.class); + AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession()); + StoreFactory storeFactory = authorizationProvider.getStoreFactory(); + UserModel userModel = event.getUser(); + ResourceStore resourceStore = storeFactory.getResourceStore(); + PolicyStore policyStore = storeFactory.getPolicyStore(); + + resourceStore.findByOwner(userModel.getId()).forEach(resource -> { + String resourceId = resource.getId(); + policyStore.findByResource(resourceId).forEach(policy -> { + if (policy.getResources().size() == 1) { + policyStore.delete(policy.getId()); + } else { + policy.removeResource(resource); + } + }); + resourceStore.delete(resourceId); + }); + } +} diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java index 8db12f8a97..49eab24a91 100644 --- a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java +++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java @@ -86,17 +86,25 @@ public class ResourceSetService { return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists."); } - String ownerId = owner.getId(); + if (owner != null) { + String ownerId = owner.getId(); - if (ownerId != null) { - if (!resourceServer.getClientId().equals(ownerId)) { - RealmModel realm = authorization.getRealm(); - KeycloakSession keycloakSession = authorization.getKeycloakSession(); - UserFederationManager users = keycloakSession.users(); - UserModel ownerModel = users.getUserByUsername(ownerId, realm); + if (ownerId != null) { + if (!resourceServer.getClientId().equals(ownerId)) { + RealmModel realm = authorization.getRealm(); + KeycloakSession keycloakSession = authorization.getKeycloakSession(); + UserFederationManager users = keycloakSession.users(); + UserModel ownerModel = users.getUserById(ownerId, realm); - if (ownerModel == null) { - return ErrorResponse.error("Owner must be a valid username or, if the resource server, the client id.", Status.BAD_REQUEST); + if (ownerModel == null) { + ownerModel = users.getUserByUsername(ownerId, realm); + } + + if (ownerModel == null) { + return ErrorResponse.error("Owner must be a valid username or user identifier. If the resource server, the client id or null.", Status.BAD_REQUEST); + } + + owner.setId(ownerModel.getId()); } } } @@ -148,7 +156,7 @@ public class ResourceSetService { if (policyModel.getResources().size() == 1) { policyStore.delete(policyModel.getId()); } else { - policyModel.addResource(resource); + policyModel.removeResource(resource); } } From d9069e0955350a528e1b8d8a553758e9cdc101c3 Mon Sep 17 00:00:00 2001 From: mhajas Date: Thu, 3 Nov 2016 08:26:50 +0100 Subject: [PATCH 18/21] KEYCLOAK-3841 Remove missing dependency --- .../integration-arquillian/tests/other/adapters/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml index 07f7c2506b..b99ccc16d3 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml @@ -332,12 +332,6 @@ ${project.version} war - - org.keycloak.testsuite - integration-arquillian-test-apps-example-camel-cdi - ${project.version} - war - ${examples.home} true From 6605ba1362176bf591196fbf874042c6ecda9017 Mon Sep 17 00:00:00 2001 From: mhajas Date: Thu, 3 Nov 2016 09:43:49 +0100 Subject: [PATCH 19/21] KEYCLOAK-3854 Move EnfrocerConfigTest out from adapter tests --- .../client}/authorization/EnforcerConfigTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) rename testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/{adapter/example => admin/client}/authorization/EnforcerConfigTest.java (90%) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/EnforcerConfigTest.java similarity index 90% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java rename to testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/EnforcerConfigTest.java index 3231beb7ea..f1e407f9f0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/EnforcerConfigTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/EnforcerConfigTest.java @@ -14,8 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.keycloak.testsuite.adapter.example.authorization; +package org.keycloak.testsuite.admin.client.authorization; +import org.junit.BeforeClass; import org.junit.Test; import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeploymentBuilder; @@ -23,6 +24,7 @@ import org.keycloak.adapters.authorization.PolicyEnforcer; import org.keycloak.representations.adapters.config.PolicyEnforcerConfig; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.ProfileAssume; import java.util.List; @@ -34,6 +36,9 @@ import static org.keycloak.testsuite.util.IOUtil.loadRealm; */ public class EnforcerConfigTest extends AbstractKeycloakTest { + @BeforeClass + public static void enabled() { ProfileAssume.assumePreview(); } + @Override public void addTestRealms(List testRealms) { RealmRepresentation realm = loadRealm(getClass().getResourceAsStream("/authorization-test/test-authz-realm.json")); From 6c5d1b92142fcb03dfec3c366fac0c126034e958 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Wed, 26 Oct 2016 08:31:16 -0200 Subject: [PATCH 20/21] [KEYCLOAK-3580] - Migrate DBus Java from Unix Socket C library to jnr-unixsocket --- federation/sssd/pom.xml | 4 + .../java/cx/ath/matthew/LibraryLoader.java | 46 ---- .../cx/ath/matthew/unix/USInputStream.java | 32 ++- .../cx/ath/matthew/unix/USOutputStream.java | 64 +++++- .../cx/ath/matthew/unix/UnixIOException.java | 43 ---- .../java/cx/ath/matthew/unix/UnixSocket.java | 127 ++--------- .../ath/matthew/unix/UnixSocketAddress.java | 86 ------- .../org/freedesktop/dbus/MessageWriter.java | 20 +- .../java/org/freedesktop/dbus/Transport.java | 213 +----------------- .../keycloak/federation/sssd/api/Sssd.java | 26 +-- pom.xml | 6 + 11 files changed, 126 insertions(+), 541 deletions(-) delete mode 100644 federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java delete mode 100644 federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java delete mode 100644 federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java diff --git a/federation/sssd/pom.xml b/federation/sssd/pom.xml index 5126ab23da..8430e7cb17 100644 --- a/federation/sssd/pom.xml +++ b/federation/sssd/pom.xml @@ -65,6 +65,10 @@ jboss-logging provided + + com.github.jnr + jnr-unixsocket + diff --git a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java b/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java deleted file mode 100644 index 4088d46ebb..0000000000 --- a/federation/sssd/src/main/java/cx/ath/matthew/LibraryLoader.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 cx.ath.matthew; - -/** - * @author Bruno Oliveira. - */ -public class LibraryLoader { - - private static final String[] PATHS = {"/usr/lib/", "/usr/lib64/", "/usr/local/lib/", "/opt/local/lib/"}; - private static final String LIBRARY_NAME = "libunix_dbus_java"; - private static final String VERSION = "0.0.8"; - private static boolean loadSucceeded; - - public static LibraryLoader load() { - for (String path : PATHS) { - try { - System.load(String.format("%s/%s.so.%s", path, LIBRARY_NAME, VERSION)); - loadSucceeded = true; - break; - } catch (UnsatisfiedLinkError e) { - loadSucceeded = false; - } - } - - return new LibraryLoader(); - } - - public boolean succeed() { - return loadSucceeded; - } -} diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java index eb143fe6a9..b11609f8a2 100644 --- a/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java +++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USInputStream.java @@ -26,25 +26,25 @@ */ package cx.ath.matthew.unix; +import jnr.unixsocket.UnixSocketChannel; + import java.io.IOException; import java.io.InputStream; +import java.nio.channels.Channels; public class USInputStream extends InputStream { public static final int MSG_DONTWAIT = 0x40; + private UnixSocketChannel channel; - private native int native_recv(int sock, byte[] b, int off, int len, int flags, int timeout) throws IOException; - - private int sock; boolean closed = false; private byte[] onebuf = new byte[1]; private UnixSocket us; - private boolean blocking = true; private int flags = 0; private int timeout = 0; - public USInputStream(int sock, UnixSocket us) { - this.sock = sock; + public USInputStream(UnixSocketChannel channel, UnixSocket us) { this.us = us; + this.channel = channel; } public void close() throws IOException { @@ -65,7 +65,8 @@ public class USInputStream extends InputStream { public int read(byte[] b, int off, int len) throws IOException { if (closed) throw new NotConnectedException(); - int count = native_recv(sock, b, off, len, flags, timeout); + int count = receive(b, off, len); + /* Yes, I really want to do this. Recv returns 0 for 'connection shut down'. * read() returns -1 for 'end of stream. * Recv returns -1 for 'EAGAIN' (all other errors cause an exception to be raised) @@ -91,4 +92,21 @@ public class USInputStream extends InputStream { public void setSoTimeout(int timeout) { this.timeout = timeout; } + + /* + * Taken from JRuby with small modifications + * @see RubyUNIXSocket.java + */ + private int receive(byte[] dataBytes, int off, int len) { + int recvStatus = -1; + try { + InputStream inputStream = Channels.newInputStream(channel); + recvStatus = inputStream.read(dataBytes, off, len); + + } catch (IOException e) { + e.printStackTrace(); + } + + return recvStatus; + } } diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java index d8c85a7718..1855b26a44 100644 --- a/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java +++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/USOutputStream.java @@ -26,22 +26,31 @@ */ package cx.ath.matthew.unix; +import jnr.constants.platform.linux.SocketLevel; +import jnr.posix.CmsgHdr; +import jnr.posix.MsgHdr; +import jnr.posix.POSIX; +import jnr.posix.POSIXFactory; +import jnr.unixsocket.UnixSocketChannel; + import java.io.IOException; import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; public class USOutputStream extends OutputStream { - private native int native_send(int sock, byte[] b, int off, int len) throws IOException; - private native int native_send(int sock, byte[][] b) throws IOException; + private UnixSocketChannel channel; private int sock; boolean closed = false; private byte[] onebuf = new byte[1]; private UnixSocket us; - public USOutputStream(int sock, UnixSocket us) { + public USOutputStream(UnixSocketChannel channel, int sock, UnixSocket us) { this.sock = sock; this.us = us; + this.channel = channel; } public void close() throws IOException { @@ -52,14 +61,9 @@ public class USOutputStream extends OutputStream { public void flush() { } // no-op, we do not buffer - public void write(byte[][] b) throws IOException { - if (closed) throw new NotConnectedException(); - native_send(sock, b); - } - public void write(byte[] b, int off, int len) throws IOException { if (closed) throw new NotConnectedException(); - native_send(sock, b, off, len); + send(sock, b, off, len); } public void write(int b) throws IOException { @@ -75,4 +79,46 @@ public class USOutputStream extends OutputStream { public UnixSocket getSocket() { return us; } + + /* + * Taken from JRuby with small modifications + * @see RubyUNIXSocket.java + */ + private void send(int sock, ByteBuffer[] outIov) { + + final POSIX posix = POSIXFactory.getNativePOSIX(); + MsgHdr outMessage = posix.allocateMsgHdr(); + + outMessage.setIov(outIov); + + CmsgHdr outControl = outMessage.allocateControl(4); + outControl.setLevel(SocketLevel.SOL_SOCKET.intValue()); + outControl.setType(0x01); + + ByteBuffer fdBuf = ByteBuffer.allocateDirect(4); + fdBuf.order(ByteOrder.nativeOrder()); + fdBuf.putInt(0, channel.getFD()); + outControl.setData(fdBuf); + + posix.sendmsg(sock, outMessage, 0); + + } + + private void send(int sock, byte[] dataBytes, int off, int len) { + ByteBuffer[] outIov = new ByteBuffer[1]; + outIov[0] = ByteBuffer.allocateDirect(dataBytes.length); + outIov[0].put(dataBytes, off, len); + outIov[0].flip(); + + send(sock, outIov); + } + + protected void send(int sock, byte[] dataBytes) { + ByteBuffer[] outIov = new ByteBuffer[1]; + outIov[0] = ByteBuffer.allocateDirect(dataBytes.length); + outIov[0].put(dataBytes); + outIov[0].flip(); + + send(sock, outIov); + } } diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java deleted file mode 100644 index 24fd20cd1f..0000000000 --- a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixIOException.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Java Unix Sockets Library - * - * Copyright (c) Matthew Johnson 2004 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * To Contact the author, please email src@matthew.ath.cx - * - */ -package cx.ath.matthew.unix; - -import java.io.IOException; - -/** - * An IO Exception which occurred during UNIX Socket IO - */ -public class UnixIOException extends IOException { - private int no; - private String message; - - public UnixIOException(int no, String message) { - super(message); - this.message = message; - this.no = no; - } -} diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java index 8851637436..7537f018ef 100644 --- a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java +++ b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocket.java @@ -26,9 +26,11 @@ */ package cx.ath.matthew.unix; -import cx.ath.matthew.LibraryLoader; import cx.ath.matthew.debug.Debug; +import jnr.unixsocket.UnixSocketAddress; +import jnr.unixsocket.UnixSocketChannel; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -37,25 +39,8 @@ import java.io.OutputStream; * Represents a UnixSocket. */ public class UnixSocket { - static { - LibraryLoader.load(); - } - private native void native_set_pass_cred(int sock, boolean passcred) throws IOException; - - private native int native_connect(String address, boolean abs) throws IOException; - - private native void native_close(int sock) throws IOException; - - private native int native_getPID(int sock); - - private native int native_getUID(int sock); - - private native int native_getGID(int sock); - - private native void native_send_creds(int sock, byte data) throws IOException; - - private native byte native_recv_creds(int sock, int[] creds) throws IOException; + private UnixSocketChannel channel; private UnixSocketAddress address = null; private USOutputStream os = null; @@ -73,8 +58,8 @@ public class UnixSocket { this.sock = sock; this.address = address; this.connected = true; - this.os = new USOutputStream(sock, this); - this.is = new USInputStream(sock, this); + this.os = new USOutputStream(channel, sock, this); + this.is = new USInputStream(channel, this); } /** @@ -98,7 +83,7 @@ public class UnixSocket { * @param address The Unix Socket address to connect to */ public UnixSocket(String address) throws IOException { - this(new UnixSocketAddress(address)); + this(new UnixSocketAddress(new File(address))); } /** @@ -108,9 +93,11 @@ public class UnixSocket { */ public void connect(UnixSocketAddress address) throws IOException { if (connected) close(); - this.sock = native_connect(address.path, address.abs); - this.os = new USOutputStream(this.sock, this); - this.is = new USInputStream(this.sock, this); + this.channel = UnixSocketChannel.open(address); + this.channel = UnixSocketChannel.open(address); + this.sock = channel.getFD(); + this.os = new USOutputStream(channel, sock, this); + this.is = new USInputStream(channel, this); this.address = address; this.connected = true; this.closed = false; @@ -123,7 +110,7 @@ public class UnixSocket { * @param address The Unix Socket address to connect to */ public void connect(String address) throws IOException { - connect(new UnixSocketAddress(address)); + connect(new UnixSocketAddress(new File(address))); } public void finalize() { @@ -138,7 +125,7 @@ public class UnixSocket { */ public synchronized void close() throws IOException { if (Debug.debug) Debug.print(Debug.INFO, "Closing socket"); - native_close(sock); + channel.close(); sock = 0; this.closed = true; this.connected = false; @@ -182,91 +169,7 @@ public class UnixSocket { */ public void sendCredentialByte(byte data) throws IOException { if (!connected) throw new NotConnectedException(); - native_send_creds(sock, data); - } - - /** - * Receive a single byte of data, with credentials. - * (Works on BSDs) - * - * @param data The byte of data to send. - * @see getPeerUID - * @see getPeerPID - * @see getPeerGID - */ - public byte recvCredentialByte() throws IOException { - if (!connected) throw new NotConnectedException(); - int[] creds = new int[]{-1, -1, -1}; - byte data = native_recv_creds(sock, creds); - pid = creds[0]; - uid = creds[1]; - gid = creds[2]; - return data; - } - - /** - * Get the credential passing status. - * (only effective on linux) - * - * @return The current status of credential passing. - * @see setPassCred - */ - public boolean getPassCred() { - return passcred; - } - - /** - * Return the uid of the remote process. - * Some data must have been received on the socket to do this. - * Either setPassCred must be called on Linux first, or recvCredentialByte - * on BSD. - * - * @return the UID or -1 if it is not available - */ - public int getPeerUID() { - if (-1 == uid) - uid = native_getUID(sock); - return uid; - } - - /** - * Return the gid of the remote process. - * Some data must have been received on the socket to do this. - * Either setPassCred must be called on Linux first, or recvCredentialByte - * on BSD. - * - * @return the GID or -1 if it is not available - */ - public int getPeerGID() { - if (-1 == gid) - gid = native_getGID(sock); - return gid; - } - - /** - * Return the pid of the remote process. - * Some data must have been received on the socket to do this. - * Either setPassCred must be called on Linux first, or recvCredentialByte - * on BSD. - * - * @return the PID or -1 if it is not available - */ - public int getPeerPID() { - if (-1 == pid) - pid = native_getPID(sock); - return pid; - } - - /** - * Set the credential passing status. - * (Only does anything on linux, for other OS, you need - * to use send/recv credentials) - * - * @param enable Set to true for credentials to be passed. - */ - public void setPassCred(boolean enable) throws IOException { - native_set_pass_cred(sock, enable); - passcred = enable; + os.send(channel.getFD(), new byte[]{ data }); } /** diff --git a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java b/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java deleted file mode 100644 index 0baba479bb..0000000000 --- a/federation/sssd/src/main/java/cx/ath/matthew/unix/UnixSocketAddress.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Java Unix Sockets Library - * - * Copyright (c) Matthew Johnson 2004 - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * To Contact the author, please email src@matthew.ath.cx - * - */ -package cx.ath.matthew.unix; - -/** - * Represents an address for a Unix Socket - */ -public class UnixSocketAddress { - String path; - boolean abs; - - /** - * Create the address. - * - * @param path The path to the Unix Socket. - * @param abs True if this should be an abstract socket. - */ - public UnixSocketAddress(String path, boolean abs) { - this.path = path; - this.abs = abs; - } - - /** - * Create the address. - * - * @param path The path to the Unix Socket. - */ - public UnixSocketAddress(String path) { - this.path = path; - this.abs = false; - } - - /** - * Return the path. - */ - public String getPath() { - return path; - } - - /** - * Returns true if this an address for an abstract socket. - */ - public boolean isAbstract() { - return abs; - } - - /** - * Return the Address as a String. - */ - public String toString() { - return "unix" + (abs ? ":abstract" : "") + ":path=" + path; - } - - public boolean equals(Object o) { - if (!(o instanceof UnixSocketAddress)) return false; - return ((UnixSocketAddress) o).path.equals(this.path); - } - - public int hashCode() { - return path.hashCode(); - } -} diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java index 45e8cb75f5..2a534263a3 100644 --- a/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java +++ b/federation/sssd/src/main/java/org/freedesktop/dbus/MessageWriter.java @@ -43,20 +43,12 @@ public class MessageWriter { if (Debug.debug) Debug.print(Debug.WARN, "Message " + m + " wire-data was null!"); return; } - if (isunix) { - if (Debug.debug) { - Debug.print(Debug.DEBUG, "Writing all " + m.getWireData().length + " buffers simultaneously to Unix Socket"); - for (byte[] buf : m.getWireData()) - Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf))); - } - ((USOutputStream) out).write(m.getWireData()); - } else - for (byte[] buf : m.getWireData()) { - if (Debug.debug) - Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf))); - if (null == buf) break; - out.write(buf); - } + for (byte[] buf : m.getWireData()) { + if (Debug.debug) + Debug.print(Debug.VERBOSE, "(" + buf + "):" + (null == buf ? "" : Hexdump.format(buf))); + if (null == buf) break; + out.write(buf); + } out.flush(); } diff --git a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java index 1745bcfec2..0c997bd021 100644 --- a/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java +++ b/federation/sssd/src/main/java/org/freedesktop/dbus/Transport.java @@ -12,7 +12,6 @@ package org.freedesktop.dbus; import cx.ath.matthew.debug.Debug; import cx.ath.matthew.unix.UnixSocket; -import cx.ath.matthew.unix.UnixSocketAddress; import cx.ath.matthew.utils.Hexdump; import java.io.BufferedReader; @@ -26,7 +25,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.Method; import java.net.InetSocketAddress; -import java.net.ServerSocket; import java.net.Socket; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -257,10 +255,8 @@ public class Transport { return new String(res); } - public static final int MODE_SERVER = 1; public static final int MODE_CLIENT = 2; - public static final int AUTH_NONE = 0; public static final int AUTH_EXTERNAL = 1; public static final int AUTH_SHA = 2; public static final int AUTH_ANON = 4; @@ -277,15 +273,12 @@ public class Transport { public static final int WAIT_DATA = 1; public static final int WAIT_OK = 2; public static final int WAIT_REJECT = 3; - public static final int WAIT_AUTH = 4; - public static final int WAIT_BEGIN = 5; public static final int AUTHENTICATED = 6; public static final int FAILED = 7; public static final int OK = 1; public static final int CONTINUE = 2; public static final int ERROR = 3; - public static final int REJECT = 4; public Command receive(InputStream s) throws IOException { StringBuffer sb = new StringBuffer(); @@ -395,89 +388,8 @@ public class Transport { } } - public String challenge = ""; public String cookie = ""; - public int do_response(int auth, String Uid, String kernelUid, Command c) { - MessageDigest md = null; - try { - md = MessageDigest.getInstance("SHA"); - } catch (NoSuchAlgorithmException NSAe) { - if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, NSAe); - return ERROR; - } - switch (auth) { - case AUTH_NONE: - switch (c.getMechs()) { - case AUTH_ANON: - return OK; - case AUTH_EXTERNAL: - if (0 == col.compare(Uid, c.getData()) && - (null == kernelUid || 0 == col.compare(Uid, kernelUid))) - return OK; - else - return ERROR; - case AUTH_SHA: - String context = COOKIE_CONTEXT; - long id = System.currentTimeMillis(); - byte[] buf = new byte[8]; - Message.marshallintBig(id, buf, 0, 8); - challenge = stupidlyEncode(md.digest(buf)); - Random r = new Random(); - r.nextBytes(buf); - cookie = stupidlyEncode(md.digest(buf)); - try { - addCookie(context, "" + id, id / 1000, cookie); - } catch (IOException IOe) { - if (Debug.debug && AbstractConnection.EXCEPTION_DEBUG) Debug.print(Debug.ERR, IOe); - } - if (Debug.debug) - Debug.print(Debug.DEBUG, "Sending challenge: " + context + ' ' + id + ' ' + challenge); - c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge)); - return CONTINUE; - default: - return ERROR; - } - case AUTH_SHA: - String[] response = stupidlyDecode(c.getData()).split(" "); - if (response.length < 2) return ERROR; - String cchal = response[0]; - String hash = response[1]; - String prehash = challenge + ":" + cchal + ":" + cookie; - byte[] buf = md.digest(prehash.getBytes()); - String posthash = stupidlyEncode(buf); - if (Debug.debug) - Debug.print(Debug.DEBUG, "Authenticating Hash; data=" + prehash + " remote hash=" + hash + " local hash=" + posthash); - if (0 == col.compare(posthash, hash)) - return OK; - else - return ERROR; - default: - return ERROR; - } - } - - public String[] getTypes(int types) { - switch (types) { - case AUTH_EXTERNAL: - return new String[]{"EXTERNAL"}; - case AUTH_SHA: - return new String[]{"DBUS_COOKIE_SHA1"}; - case AUTH_ANON: - return new String[]{"ANONYMOUS"}; - case AUTH_SHA + AUTH_EXTERNAL: - return new String[]{"EXTERNAL", "DBUS_COOKIE_SHA1"}; - case AUTH_SHA + AUTH_ANON: - return new String[]{"ANONYMOUS", "DBUS_COOKIE_SHA1"}; - case AUTH_EXTERNAL + AUTH_ANON: - return new String[]{"ANONYMOUS", "EXTERNAL"}; - case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA: - return new String[]{"ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"}; - default: - return new String[]{}; - } - } - /** * performs SASL auth on the given streams. * Mode selects whether to run as a SASL server or client. @@ -488,7 +400,6 @@ public class Transport { public boolean auth(int mode, int types, String guid, OutputStream out, InputStream in, UnixSocket us) throws IOException { String username = System.getProperty("user.name"); String Uid = null; - String kernelUid = null; try { Class c = Class.forName("com.sun.security.auth.module.UnixSystem"); Method m = c.getMethod("getUid"); @@ -618,110 +529,6 @@ public class Transport { state = FAILED; } break; - case MODE_SERVER: - switch (state) { - case INITIAL_STATE: - byte[] buf = new byte[1]; - if (null == us) { - in.read(buf); - } else { - buf[0] = us.recvCredentialByte(); - int kuid = us.getPeerUID(); - if (kuid >= 0) - kernelUid = stupidlyEncode("" + kuid); - } - if (0 != buf[0]) state = FAILED; - else state = WAIT_AUTH; - break; - case WAIT_AUTH: - c = receive(in); - switch (c.getCommand()) { - case COMMAND_AUTH: - if (null == c.getData()) { - send(out, COMMAND_REJECTED, getTypes(types)); - } else { - switch (do_response(current, Uid, kernelUid, c)) { - case CONTINUE: - send(out, COMMAND_DATA, c.getResponse()); - current = c.getMechs(); - state = WAIT_DATA; - break; - case OK: - send(out, COMMAND_OK, guid); - state = WAIT_BEGIN; - current = 0; - break; - case REJECT: - send(out, COMMAND_REJECTED, getTypes(types)); - current = 0; - break; - } - } - break; - case COMMAND_ERROR: - send(out, COMMAND_REJECTED, getTypes(types)); - break; - case COMMAND_BEGIN: - state = FAILED; - break; - default: - send(out, COMMAND_ERROR, "Got invalid command"); - break; - } - break; - case WAIT_DATA: - c = receive(in); - switch (c.getCommand()) { - case COMMAND_DATA: - switch (do_response(current, Uid, kernelUid, c)) { - case CONTINUE: - send(out, COMMAND_DATA, c.getResponse()); - state = WAIT_DATA; - break; - case OK: - send(out, COMMAND_OK, guid); - state = WAIT_BEGIN; - current = 0; - break; - case REJECT: - send(out, COMMAND_REJECTED, getTypes(types)); - current = 0; - break; - } - break; - case COMMAND_ERROR: - case COMMAND_CANCEL: - send(out, COMMAND_REJECTED, getTypes(types)); - state = WAIT_AUTH; - break; - case COMMAND_BEGIN: - state = FAILED; - break; - default: - send(out, COMMAND_ERROR, "Got invalid command"); - break; - } - break; - case WAIT_BEGIN: - c = receive(in); - switch (c.getCommand()) { - case COMMAND_ERROR: - case COMMAND_CANCEL: - send(out, COMMAND_REJECTED, getTypes(types)); - state = WAIT_AUTH; - break; - case COMMAND_BEGIN: - state = AUTHENTICATED; - break; - default: - send(out, COMMAND_ERROR, "Got invalid command"); - break; - } - break; - default: - state = FAILED; - } - break; default: return false; } @@ -781,25 +588,15 @@ public class Transport { types = SASL.AUTH_EXTERNAL; mode = SASL.MODE_CLIENT; us = new UnixSocket(); - if (null != address.getParameter("abstract")) - us.connect(new UnixSocketAddress(address.getParameter("abstract"), true)); - else if (null != address.getParameter("path")) - us.connect(new UnixSocketAddress(address.getParameter("path"), false)); - us.setPassCred(true); + if (null != address.getParameter("path")) + us.connect(new jnr.unixsocket.UnixSocketAddress(new File(address.getParameter("path")))); in = us.getInputStream(); out = us.getOutputStream(); } else if ("tcp".equals(address.getType())) { types = SASL.AUTH_SHA; - if (null != address.getParameter("listen")) { - mode = SASL.MODE_SERVER; - ServerSocket ss = new ServerSocket(); - ss.bind(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port")))); - s = ss.accept(); - } else { - mode = SASL.MODE_CLIENT; - s = new Socket(); - s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port")))); - } + mode = SASL.MODE_CLIENT; + s = new Socket(); + s.connect(new InetSocketAddress(address.getParameter("host"), Integer.parseInt(address.getParameter("port")))); in = s.getInputStream(); out = s.getOutputStream(); } else { diff --git a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java index 065eb98842..5d62ce4ba7 100644 --- a/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java +++ b/federation/sssd/src/main/java/org/keycloak/federation/sssd/api/Sssd.java @@ -17,8 +17,6 @@ package org.keycloak.federation.sssd.api; -import cx.ath.matthew.LibraryLoader; -import org.freedesktop.DBus; import org.freedesktop.dbus.DBusConnection; import org.freedesktop.dbus.Variant; import org.freedesktop.dbus.exceptions.DBusException; @@ -26,6 +24,9 @@ import org.freedesktop.sssd.infopipe.InfoPipe; import org.freedesktop.sssd.infopipe.User; import org.jboss.logging.Logger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -110,24 +111,17 @@ public class Sssd { return userGroups; } - public static boolean isAvailable(){ + public static boolean isAvailable() { boolean sssdAvailable = false; try { - if (LibraryLoader.load().succeed()) { - DBusConnection connection = DBusConnection.getConnection(DBusConnection.SYSTEM); - DBus dbus = connection.getRemoteObject(DBus.BUSNAME, DBus.OBJECTPATH, DBus.class); - sssdAvailable = Arrays.asList(dbus.ListNames()).contains(InfoPipe.BUSNAME); - if (!sssdAvailable) { - logger.debugv("SSSD is not available in your system. Federation provider will be disabled."); - } else { - sssdAvailable = true; - } - connection.disconnect(); + Path path = Paths.get("/etc/sssd"); + if (!Files.exists(path)) { + logger.debugv("SSSD is not available in your system. Federation provider will be disabled."); } else { - logger.debugv("libunix_dbus_java not found. Federation provider will be disabled."); + sssdAvailable = true; } - } catch (DBusException e) { - logger.error("Failed to check the status of SSSD", e); + } catch (Exception e) { + logger.error("SSSD check failed", e); } return sssdAvailable; } diff --git a/pom.xml b/pom.xml index a5e376dd1e..8a61e5b0b4 100755 --- a/pom.xml +++ b/pom.xml @@ -98,6 +98,7 @@ 1.0.2.Final 4.0.4 4.1.0 + 0.14 1.3.1b @@ -700,6 +701,11 @@ jna ${jna.version} + + com.github.jnr + jnr-unixsocket + ${jnr.version} + org.keycloak keycloak-ldap-federation From 66698f60d49da9909cea4f0e7fdc4e8e22885e9a Mon Sep 17 00:00:00 2001 From: Stan Silvert Date: Fri, 4 Nov 2016 15:32:19 -0400 Subject: [PATCH 21/21] KEYCLOAK-3816: Tweak CSS for 1280 x 720 display --- .../main/resources/theme/keycloak/login/resources/css/login.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css index 54eb79655c..7b202e131b 100644 --- a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css +++ b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css @@ -244,7 +244,7 @@ ol#kc-totp-settings li:first-of-type { .zocial.microsoft {background-color: #0052a4; color: #fff;} .zocial.microsoft:before { content: "\f15d"; } -@media (min-width: 801px) { +@media (min-width: 1281px) { #kc-container-wrapper { bottom: 13%; }