keycloak-developers
Changes
connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java 4(+4 -0)
core/pom.xml 41(+41 -0)
dependencies/server-all/pom.xml 6(+6 -0)
dependencies/server-min/pom.xml 4(+4 -0)
distribution/osgi/jaas/pom.xml 6(+3 -3)
distribution/osgi/pom.xml 2(+1 -1)
distribution/osgi/thirdparty/pom.xml 53(+14 -39)
docbook/reference/en/en-US/modules/jaas.xml 37(+37 -0)
examples/cordova/www/index.html 25(+22 -3)
examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java 4(+3 -1)
examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java 2(+1 -1)
examples/demo-template/README.md 12(+7 -5)
examples/fuse/camel/pom.xml 79(+79 -0)
examples/fuse/customer-app-fuse/pom.xml 121(+121 -0)
examples/fuse/cxf-jaxrs/pom.xml 86(+86 -0)
examples/fuse/cxf-jaxws/pom.xml 107(+107 -0)
examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPersonResponse.java 120(+120 -0)
examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/UnknownPersonFault.java 64(+64 -0)
examples/fuse/features/pom.xml 62(+62 -0)
examples/fuse/pom.xml 37(+37 -0)
examples/fuse/product-app-fuse/pom.xml 83(+83 -0)
examples/fuse/product-app-fuse/src/main/java/org/keycloak/example/ProductPortalServlet.java 95(+95 -0)
examples/fuse/README.md 132(+132 -0)
examples/fuse/testrealm.json 135(+135 -0)
examples/multi-tenant/src/main/java/org/keycloak/example/multitenant/boundary/ProtectedServlet.java 9(+5 -4)
examples/pom.xml 1(+1 -0)
examples/README.md 10(+10 -0)
examples/saml/post-basic/README.md 2(+1 -1)
forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js 11(+6 -5)
forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js 21(+7 -14)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html 2(+1 -1)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html 2(+1 -1)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html 2(+1 -1)
forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-detail.html 2(+1 -1)
integration/adapter-core/pom.xml 44(+44 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/BearerTokenLoginModule.java 2(+1 -1)
integration/installed/pom.xml 4(+4 -0)
integration/jetty/jetty8.1/pom.xml 41(+41 -0)
integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java 1(+1 -0)
integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java 1(+1 -0)
integration/jetty/jetty9.1/pom.xml 42(+42 -0)
integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java 1(+1 -0)
integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java 1(+1 -0)
integration/jetty/jetty9.2/pom.xml 42(+42 -0)
integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java 2(+1 -1)
integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java 1(+1 -0)
integration/jetty/jetty-core/pom.xml 42(+42 -0)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractJettySessionTokenStore.java 5(+1 -4)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java 18(+14 -4)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyCookieTokenStore.java 2(+1 -1)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyHttpFacade.java 2(+1 -1)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyRequestAuthenticator.java 2(+1 -1)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/JettyUserSessionManagement.java 2(+1 -1)
integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/WrappingSessionHandler.java 30(+30 -0)
integration/osgi-adapter/pom.xml 104(+104 -0)
integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java 163(+163 -0)
integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/ServletUnregistrationService.java 100(+100 -0)
integration/pom.xml 1(+1 -0)
pom.xml 20(+19 -1)
project-integrations/aerogear-ups/app/src/main/java/org/keycloak/example/BootstrapListener.java 33(+0 -33)
project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 1(+1 -0)
project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml 5(+4 -1)
testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java 2(+1 -1)
Details
diff --git a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
index 5a00c74..2e7841a 100755
--- a/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
+++ b/connections/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
@@ -117,6 +117,10 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
logger.trace("Updating database");
JpaUpdaterProvider updater = session.getProvider(JpaUpdaterProvider.class);
+ if (updater == null) {
+ throw new RuntimeException("Can't update database: JPA updater provider not found");
+ }
+
connection = getConnection();
if (databaseSchema.equals("update")) {
core/pom.xml 41(+41 -0)
diff --git a/core/pom.xml b/core/pom.xml
index 99a102e..fb19e6c 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -11,11 +11,19 @@
<artifactId>keycloak-core</artifactId>
<name>Keycloak Core</name>
+ <packaging>jar</packaging>
<description/>
<properties>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
+ <keycloak.osgi.export>
+ org.keycloak.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ net.iharder;version=${base64.version},
+ *;resolution:=optional
+ </keycloak.osgi.import>
</properties>
<dependencies>
<dependency>
@@ -60,6 +68,39 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java
index 975da61..784e409 100755
--- a/core/src/main/java/org/keycloak/representations/IDToken.java
+++ b/core/src/main/java/org/keycloak/representations/IDToken.java
@@ -1,96 +1,23 @@
package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.annotate.JsonUnwrapped;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class IDToken extends JsonWebToken {
+
@JsonProperty("nonce")
protected String nonce;
- @JsonProperty("name")
- protected String name;
-
- @JsonProperty("given_name")
- protected String givenName;
-
- @JsonProperty("family_name")
- protected String familyName;
-
- @JsonProperty("middle_name")
- protected String middleName;
-
- @JsonProperty("nickname")
- protected String nickName;
-
- @JsonProperty("preferred_username")
- protected String preferredUsername;
-
- @JsonProperty("profile")
- protected String profile;
-
- @JsonProperty("picture")
- protected String picture;
-
- @JsonProperty("website")
- protected String website;
-
- @JsonProperty("email")
- protected String email;
-
- @JsonProperty("email_verified")
- protected Boolean emailVerified;
-
- @JsonProperty("gender")
- protected String gender;
-
- @JsonProperty("birthdate")
- protected String birthdate;
-
- @JsonProperty("zoneinfo")
- protected String zoneinfo;
-
- @JsonProperty("locale")
- protected String locale;
-
- @JsonProperty("phone_number")
- protected String phoneNumber;
-
- @JsonProperty("phone_number_verified")
- protected Boolean phoneNumberVerified;
-
- @JsonProperty("address")
- protected String address;
-
- @JsonProperty("updated_at")
- protected Long updatedAt;
-
- @JsonProperty("formatted")
- protected String formattedAddress;
-
- @JsonProperty("street_address")
- protected String streetAddress;
-
- @JsonProperty("locality")
- protected String locality;
-
- @JsonProperty("region")
- protected String region;
-
- @JsonProperty("postal_code")
- protected String postalCode;
-
- @JsonProperty("country")
- protected String country;
-
- @JsonProperty("claims_locales")
- protected String claimsLocales;
-
@JsonProperty("session_state")
protected String sessionState;
+ @JsonUnwrapped
+ protected UserClaimSet userClaimSet = new UserClaimSet();
+
public String getNonce() {
return nonce;
}
@@ -99,214 +26,6 @@ public class IDToken extends JsonWebToken {
this.nonce = nonce;
}
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getGivenName() {
- return givenName;
- }
-
- public void setGivenName(String givenName) {
- this.givenName = givenName;
- }
-
- public String getFamilyName() {
- return familyName;
- }
-
- public void setFamilyName(String familyName) {
- this.familyName = familyName;
- }
-
- public String getMiddleName() {
- return middleName;
- }
-
- public void setMiddleName(String middleName) {
- this.middleName = middleName;
- }
-
- public String getNickName() {
- return nickName;
- }
-
- public void setNickName(String nickName) {
- this.nickName = nickName;
- }
-
- public String getPreferredUsername() {
- return preferredUsername;
- }
-
- public void setPreferredUsername(String preferredUsername) {
- this.preferredUsername = preferredUsername;
- }
-
- public String getProfile() {
- return profile;
- }
-
- public void setProfile(String profile) {
- this.profile = profile;
- }
-
- public String getPicture() {
- return picture;
- }
-
- public void setPicture(String picture) {
- this.picture = picture;
- }
-
- public String getWebsite() {
- return website;
- }
-
- public void setWebsite(String website) {
- this.website = website;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
-
- public Boolean getEmailVerified() {
- return emailVerified;
- }
-
- public void setEmailVerified(Boolean emailVerified) {
- this.emailVerified = emailVerified;
- }
-
- public String getGender() {
- return gender;
- }
-
- public void setGender(String gender) {
- this.gender = gender;
- }
-
- public String getBirthdate() {
- return birthdate;
- }
-
- public void setBirthdate(String birthdate) {
- this.birthdate = birthdate;
- }
-
- public String getZoneinfo() {
- return zoneinfo;
- }
-
- public void setZoneinfo(String zoneinfo) {
- this.zoneinfo = zoneinfo;
- }
-
- public String getLocale() {
- return locale;
- }
-
- public void setLocale(String locale) {
- this.locale = locale;
- }
-
- public String getPhoneNumber() {
- return phoneNumber;
- }
-
- public void setPhoneNumber(String phoneNumber) {
- this.phoneNumber = phoneNumber;
- }
-
- public Boolean getPhoneNumberVerified() {
- return phoneNumberVerified;
- }
-
- public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
- this.phoneNumberVerified = phoneNumberVerified;
- }
-
- public String getAddress() {
- return address;
- }
-
- public void setAddress(String address) {
- this.address = address;
- }
-
- public Long getUpdatedAt() {
- return updatedAt;
- }
-
- public void setUpdatedAt(Long updatedAt) {
- this.updatedAt = updatedAt;
- }
-
- public String getFormattedAddress() {
- return formattedAddress;
- }
-
- public void setFormattedAddress(String formattedAddress) {
- this.formattedAddress = formattedAddress;
- }
-
- public String getStreetAddress() {
- return streetAddress;
- }
-
- public void setStreetAddress(String streetAddress) {
- this.streetAddress = streetAddress;
- }
-
- public String getLocality() {
- return locality;
- }
-
- public void setLocality(String locality) {
- this.locality = locality;
- }
-
- public String getRegion() {
- return region;
- }
-
- public void setRegion(String region) {
- this.region = region;
- }
-
- public String getPostalCode() {
- return postalCode;
- }
-
- public void setPostalCode(String postalCode) {
- this.postalCode = postalCode;
- }
-
- public String getCountry() {
- return country;
- }
-
- public void setCountry(String country) {
- this.country = country;
- }
-
- public String getClaimsLocales() {
- return claimsLocales;
- }
-
- public void setClaimsLocales(String claimsLocales) {
- this.claimsLocales = claimsLocales;
- }
-
public String getSessionState() {
return sessionState;
}
@@ -314,4 +33,12 @@ public class IDToken extends JsonWebToken {
public void setSessionState(String sessionState) {
this.sessionState = sessionState;
}
+
+ public UserClaimSet getUserClaimSet() {
+ return this.userClaimSet;
+ }
+
+ public void setUserClaimSet(UserClaimSet userClaimSet) {
+ this.userClaimSet = userClaimSet;
+ }
}
diff --git a/core/src/main/java/org/keycloak/representations/JsonWebToken.java b/core/src/main/java/org/keycloak/representations/JsonWebToken.java
index 42e9328..d0a4e9d 100755
--- a/core/src/main/java/org/keycloak/representations/JsonWebToken.java
+++ b/core/src/main/java/org/keycloak/representations/JsonWebToken.java
@@ -127,6 +127,10 @@ public class JsonWebToken implements Serializable {
return this;
}
+ public void setSubject(String subject) {
+ this.subject = subject;
+ }
+
public String getType() {
return type;
}
diff --git a/core/src/main/java/org/keycloak/representations/UserClaimSet.java b/core/src/main/java/org/keycloak/representations/UserClaimSet.java
new file mode 100644
index 0000000..c647269
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/UserClaimSet.java
@@ -0,0 +1,331 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.representations;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * @author pedroigor
+ */
+public class UserClaimSet {
+
+ @JsonProperty("sub")
+ protected String sub;
+
+ @JsonProperty("name")
+ protected String name;
+
+ @JsonProperty("given_name")
+ protected String givenName;
+
+ @JsonProperty("family_name")
+ protected String familyName;
+
+ @JsonProperty("middle_name")
+ protected String middleName;
+
+ @JsonProperty("nickname")
+ protected String nickName;
+
+ @JsonProperty("preferred_username")
+ protected String preferredUsername;
+
+ @JsonProperty("profile")
+ protected String profile;
+
+ @JsonProperty("picture")
+ protected String picture;
+
+ @JsonProperty("website")
+ protected String website;
+
+ @JsonProperty("email")
+ protected String email;
+
+ @JsonProperty("email_verified")
+ protected Boolean emailVerified;
+
+ @JsonProperty("gender")
+ protected String gender;
+
+ @JsonProperty("birthdate")
+ protected String birthdate;
+
+ @JsonProperty("zoneinfo")
+ protected String zoneinfo;
+
+ @JsonProperty("locale")
+ protected String locale;
+
+ @JsonProperty("phone_number")
+ protected String phoneNumber;
+
+ @JsonProperty("phone_number_verified")
+ protected Boolean phoneNumberVerified;
+
+ @JsonProperty("address")
+ protected String address;
+
+ @JsonProperty("updated_at")
+ protected Long updatedAt;
+
+ @JsonProperty("formatted")
+ protected String formattedAddress;
+
+ @JsonProperty("street_address")
+ protected String streetAddress;
+
+ @JsonProperty("locality")
+ protected String locality;
+
+ @JsonProperty("region")
+ protected String region;
+
+ @JsonProperty("postal_code")
+ protected String postalCode;
+
+ @JsonProperty("country")
+ protected String country;
+
+ @JsonProperty("claims_locales")
+ protected String claimsLocales;
+
+ public String getSubject() {
+ return this.sub;
+ }
+
+ public void setSubject(String subject) {
+ this.sub = subject;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getGivenName() {
+ return this.givenName;
+ }
+
+ public void setGivenName(String givenName) {
+ this.givenName = givenName;
+ }
+
+ public String getFamilyName() {
+ return this.familyName;
+ }
+
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ public String getMiddleName() {
+ return this.middleName;
+ }
+
+ public void setMiddleName(String middleName) {
+ this.middleName = middleName;
+ }
+
+ public String getNickName() {
+ return this.nickName;
+ }
+
+ public void setNickName(String nickName) {
+ this.nickName = nickName;
+ }
+
+ public String getPreferredUsername() {
+ return this.preferredUsername;
+ }
+
+ public void setPreferredUsername(String preferredUsername) {
+ this.preferredUsername = preferredUsername;
+ }
+
+ public String getProfile() {
+ return this.profile;
+ }
+
+ public void setProfile(String profile) {
+ this.profile = profile;
+ }
+
+ public String getPicture() {
+ return this.picture;
+ }
+
+ public void setPicture(String picture) {
+ this.picture = picture;
+ }
+
+ public String getWebsite() {
+ return this.website;
+ }
+
+ public void setWebsite(String website) {
+ this.website = website;
+ }
+
+ public String getEmail() {
+ return this.email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public Boolean getEmailVerified() {
+ return this.emailVerified;
+ }
+
+ public void setEmailVerified(Boolean emailVerified) {
+ this.emailVerified = emailVerified;
+ }
+
+ public String getGender() {
+ return this.gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public String getBirthdate() {
+ return this.birthdate;
+ }
+
+ public void setBirthdate(String birthdate) {
+ this.birthdate = birthdate;
+ }
+
+ public String getZoneinfo() {
+ return this.zoneinfo;
+ }
+
+ public void setZoneinfo(String zoneinfo) {
+ this.zoneinfo = zoneinfo;
+ }
+
+ public String getLocale() {
+ return this.locale;
+ }
+
+ public void setLocale(String locale) {
+ this.locale = locale;
+ }
+
+ public String getPhoneNumber() {
+ return this.phoneNumber;
+ }
+
+ public void setPhoneNumber(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ }
+
+ public Boolean getPhoneNumberVerified() {
+ return this.phoneNumberVerified;
+ }
+
+ public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
+ this.phoneNumberVerified = phoneNumberVerified;
+ }
+
+ public String getAddress() {
+ return this.address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public Long getUpdatedAt() {
+ return this.updatedAt;
+ }
+
+ public void setUpdatedAt(Long updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public String getSub() {
+ return this.sub;
+ }
+
+ public void setSub(String sub) {
+ this.sub = sub;
+ }
+
+ public String getFormattedAddress() {
+ return this.formattedAddress;
+ }
+
+ public void setFormattedAddress(String formattedAddress) {
+ this.formattedAddress = formattedAddress;
+ }
+
+ public String getStreetAddress() {
+ return this.streetAddress;
+ }
+
+ public void setStreetAddress(String streetAddress) {
+ this.streetAddress = streetAddress;
+ }
+
+ public String getLocality() {
+ return this.locality;
+ }
+
+ public void setLocality(String locality) {
+ this.locality = locality;
+ }
+
+ public String getRegion() {
+ return this.region;
+ }
+
+ public void setRegion(String region) {
+ this.region = region;
+ }
+
+ public String getPostalCode() {
+ return this.postalCode;
+ }
+
+ public void setPostalCode(String postalCode) {
+ this.postalCode = postalCode;
+ }
+
+ public String getCountry() {
+ return this.country;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getClaimsLocales() {
+ return this.claimsLocales;
+ }
+
+ public void setClaimsLocales(String claimsLocales) {
+ this.claimsLocales = claimsLocales;
+ }
+}
diff --git a/core/src/main/java/org/keycloak/representations/UserInfo.java b/core/src/main/java/org/keycloak/representations/UserInfo.java
new file mode 100644
index 0000000..3112981
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/UserInfo.java
@@ -0,0 +1,25 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.representations;
+
+/**
+ * @author pedroigor
+ */
+public class UserInfo extends UserClaimSet {
+
+}
diff --git a/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java b/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
index f2ec502..e5a332d 100755
--- a/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
+++ b/core/src/test/java/org/keycloak/SkeletonKeyTokenTest.java
@@ -6,6 +6,7 @@ import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.UserClaimSet;
import org.keycloak.representations.IDToken;
import org.keycloak.util.JsonSerialization;
@@ -58,7 +59,9 @@ public class SkeletonKeyTokenTest {
public void testSerialization() throws Exception {
AccessToken token = createSimpleToken();
IDToken idToken = new IDToken();
- idToken.setEmail("joe@email.cz");
+ UserClaimSet claimSet = idToken.getUserClaimSet();
+
+ claimSet.setEmail("joe@email.cz");
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
@@ -95,7 +98,7 @@ public class SkeletonKeyTokenTest {
Assert.assertEquals("111", token.getId());
Assert.assertTrue(token.getResourceAccess("foo").isUserInRole("admin"));
Assert.assertTrue(token.getResourceAccess("bar").isUserInRole("user"));
- Assert.assertEquals("joe@email.cz", idToken.getEmail());
+ Assert.assertEquals("joe@email.cz", claimSet.getEmail());
Assert.assertEquals("acme", ctx.getRealm());
ois.close();
}
dependencies/server-all/pom.xml 6(+6 -0)
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index eb1fe46..5d5576b 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -194,6 +194,12 @@
<dependency>
<groupId>de.idyl</groupId>
<artifactId>winzipaes</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
dependencies/server-min/pom.xml 4(+4 -0)
diff --git a/dependencies/server-min/pom.xml b/dependencies/server-min/pom.xml
index 9c90478..b269f35 100755
--- a/dependencies/server-min/pom.xml
+++ b/dependencies/server-min/pom.xml
@@ -25,6 +25,10 @@
<artifactId>base64</artifactId>
</dependency>
<dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core-jaxrs</artifactId>
<version>${project.version}</version>
diff --git a/distribution/examples-docs-zip/build.xml b/distribution/examples-docs-zip/build.xml
index 503dc8e..3725160 100755
--- a/distribution/examples-docs-zip/build.xml
+++ b/distribution/examples-docs-zip/build.xml
@@ -93,6 +93,12 @@
<exclude name="**/README.md"/>
</fileset>
</copy>
+ <copy todir="target/examples/fuse" overwrite="true">
+ <fileset dir="../../examples/fuse">
+ <exclude name="**/target/**"/>
+ <exclude name="**/*.iml"/>
+ </fileset>
+ </copy>
<copy file="../../examples/README.md" tofile="target/examples/README.md"/>
<move file="target/examples/unconfigured-demo/README.md.unconfigured" tofile="target/examples/unconfigured-demo/README.md"/>
<move file="target/examples/unconfigured-demo/customer-app/src/main/webapp/WEB-INF/web.xml.unconfigured" tofile="target/examples/unconfigured-demo/customer-app/src/main/webapp/WEB-INF/web.xml"/>
diff --git a/distribution/osgi/features/src/main/resources/features.xml b/distribution/osgi/features/src/main/resources/features.xml
index f72ac8d..d56602b 100644
--- a/distribution/osgi/features/src/main/resources/features.xml
+++ b/distribution/osgi/features/src/main/resources/features.xml
@@ -1,15 +1,53 @@
<?xml version='1.0' encoding='UTF-8'?>
<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="keycloak-${project.version}">
- <feature name="keycloak-core-adapter" version="${project.version}" resolver="(obr)">
- <details>The keycloak core adapter stuff</details>
- <bundle>mvn:org.keycloak/keycloak-osgi-core-adapter/${project.version}</bundle>
+ <feature name="keycloak-adapter-core" version="${project.version}" resolver="(obr)">
+ <details>The keycloak adapter core stuff</details>
+ <bundle dependency="true">mvn:org.keycloak/keycloak-osgi-thirdparty/${project.version}</bundle>
+ <bundle dependency="true">mvn:org.bouncycastle/bcprov-jdk16/${bouncycastle.version}</bundle>
+ <bundle dependency="true">mvn:org.codehaus.jackson/jackson-core-asl/${jackson.version}</bundle>
+ <bundle dependency="true">mvn:org.codehaus.jackson/jackson-mapper-asl/${jackson.version}</bundle>
+ <bundle dependency="true">mvn:org.codehaus.jackson/jackson-xc/${jackson.version}</bundle>
+ <bundle dependency="true">mvn:org.jboss.logging/jboss-logging/${jboss.logging.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-core/${project.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-adapter-core/${project.version}</bundle>
+ </feature>
+
+ <feature name="keycloak-osgi-adapter" version="${project.version}" resolver="(obr)">
+ <details>The keycloak adapter core stuff</details>
+ <feature>keycloak-adapter-core</feature>
+ <feature version="[2.3,4)">http-whiteboard</feature>
+ <bundle>mvn:org.keycloak/keycloak-osgi-adapter/${project.version}</bundle>
+ </feature>
+
+ <feature name="keycloak-jetty8-adapter" version="${project.version}" resolver="(obr)">
+ <details>The keycloak Jetty8 adapter</details>
+ <feature>keycloak-adapter-core</feature>
+ <feature version="[8.1,9)">jetty</feature>
+ <bundle>mvn:org.keycloak/keycloak-jetty-core/${project.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-jetty81-adapter/${project.version}</bundle>
</feature>
<feature name="keycloak-jaas" version="${project.version}" resolver="(obr)">
<details>The keycloak JAAS configuration</details>
- <feature>keycloak-core-adapter</feature>
+ <feature>keycloak-adapter-core</feature>
<bundle>mvn:org.keycloak/keycloak-osgi-jaas/${project.version}</bundle>
</feature>
+ <feature name="keycloak" version="${project.version}" resolver="(obr)">
+ <details>The keycloak adapter core stuff</details>
+ <feature>keycloak-osgi-adapter</feature>
+ <feature>keycloak-jetty8-adapter</feature>
+ <feature>keycloak-jaas</feature>
+ </feature>
+
+ <!-- This is just simplification to upgrade paxweb to 3.1.2 in JBoss Fuse 6.1 or Karaf 2.3.X environment -->
+ <feature name="keycloak-pax-web-upgrade" version="${project.version}" resolver="(obr)">
+ <details>This is just simplification to upgrade paxweb to 3.1.2 in JBoss Fuse 6.1 or Karaf 2.3.X environment</details>
+ <bundle>mvn:org.ow2.asm/asm-all/5.0</bundle>
+ <bundle>mvn:org.apache.xbean/xbean-bundleutils/3.18</bundle>
+ <bundle>mvn:org.apache.xbean/xbean-reflect/3.18</bundle>
+ <bundle>mvn:org.apache.xbean/xbean-finder/3.18</bundle>
+ </feature>
+
</features>
\ No newline at end of file
distribution/osgi/jaas/pom.xml 6(+3 -3)
diff --git a/distribution/osgi/jaas/pom.xml b/distribution/osgi/jaas/pom.xml
index 8604f65..4962336 100755
--- a/distribution/osgi/jaas/pom.xml
+++ b/distribution/osgi/jaas/pom.xml
@@ -7,7 +7,7 @@
<version>1.2.0.Beta1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath>
</parent>
- <name>Keycloak OSGI JAAS</name>
+ <name>Keycloak OSGI JAAS Realm Configuration</name>
<description/>
<modelVersion>4.0.0</modelVersion>
@@ -27,7 +27,7 @@
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-osgi-core-adapter</artifactId>
+ <artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
@@ -53,7 +53,7 @@
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
<Embed-Transitive>false</Embed-Transitive>
<Bundle-ClassPath>.</Bundle-ClassPath> -->
- <Bundle-Name>${project.description}</Bundle-Name>
+ <Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package>
distribution/osgi/pom.xml 2(+1 -1)
diff --git a/distribution/osgi/pom.xml b/distribution/osgi/pom.xml
index a2e1e83..eb6f64d 100755
--- a/distribution/osgi/pom.xml
+++ b/distribution/osgi/pom.xml
@@ -17,7 +17,7 @@
<modules>
<module>features</module>
<module>jaas</module>
- <module>core-adapter</module>
+ <module>thirdparty</module>
</modules>
</project>
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/master.xml b/docbook/reference/en/en-US/master.xml
index e6cd953..7b72d6a 100755
--- a/docbook/reference/en/en-US/master.xml
+++ b/docbook/reference/en/en-US/master.xml
@@ -14,9 +14,11 @@
<!ENTITY TomcatAdapter SYSTEM "modules/tomcat-adapter.xml">
<!ENTITY Jetty9Adapter SYSTEM "modules/jetty9-adapter.xml">
<!ENTITY Jetty8Adapter SYSTEM "modules/jetty8-adapter.xml">
+ <!ENTITY FuseAdapter SYSTEM "modules/fuse-adapter.xml">
<!ENTITY InstalledApplications SYSTEM "modules/installed-applications.xml">
<!ENTITY Logout SYSTEM "modules/logout.xml">
<!ENTITY SAML SYSTEM "modules/saml.xml">
+ <!ENTITY JAAS SYSTEM "modules/jaas.xml">
<!ENTITY SocialConfig SYSTEM "modules/social-config.xml">
<!ENTITY SocialFacebook SYSTEM "modules/social-facebook.xml">
<!ENTITY SocialGitHub SYSTEM "modules/social-github.xml">
@@ -91,10 +93,12 @@ This one is short
&TomcatAdapter;
&Jetty9Adapter;
&Jetty8Adapter;
+ &FuseAdapter;
&JavascriptAdapter;
&InstalledApplications;
&Logout;
&MultiTenancy;
+ &JAAS;
</chapter>
<chapter>
diff --git a/docbook/reference/en/en-US/modules/adapter-config.xml b/docbook/reference/en/en-US/modules/adapter-config.xml
index 448f6ca..a9d4e08 100755
--- a/docbook/reference/en/en-US/modules/adapter-config.xml
+++ b/docbook/reference/en/en-US/modules/adapter-config.xml
@@ -204,7 +204,7 @@
<listitem>
<para>
Specify the credentials of the application. This is an object notation where the key
- is the credential type and the value if the value of the credential type. Currently only
+ is the credential type and the value is the value of the credential type. Currently only
<literal>password</literal>
is supported.
This is <emphasis>REQUIRED</emphasis>.
@@ -374,7 +374,7 @@
<term>principal-attribute</term>
<listitem>
<para>
- OpenID Connection ID Token attribute to populate the UserPrincipal name with. If token attribute is null, defaults to <literal>sub</literal>
+ OpenID Connection ID Token attribute to populate the UserPrincipal name with. If token attribute is null, defaults to <literal>sub</literal>.
Possible values are <literal>sub</literal>, <literal>preferred_username</literal>, <literal>email</literal>, <literal>name</literal>, <literal>nickname</literal>, <literal>given_name</literal>, <literal>family_name</literal>.
</para>
</listitem>
diff --git a/docbook/reference/en/en-US/modules/application-clustering.xml b/docbook/reference/en/en-US/modules/application-clustering.xml
index 1531d1e..f332338 100644
--- a/docbook/reference/en/en-US/modules/application-clustering.xml
+++ b/docbook/reference/en/en-US/modules/application-clustering.xml
@@ -95,7 +95,7 @@
<para>
This would mean that browser requests (like redirecting to Keycloak login screen) will be still resolved relatively
to current request URI like <emphasis>https://loadbalancer.com/myapp</emphasis>, but backend (out-of-bound) requests between keycloak
- and your app are send always to same cluster host with application .
+ and your app are sent always to same cluster host with application .
</para>
<para>
Note that additionally to network optimization,
diff --git a/docbook/reference/en/en-US/modules/clustering.xml b/docbook/reference/en/en-US/modules/clustering.xml
index 350c47f..108c7f2 100755
--- a/docbook/reference/en/en-US/modules/clustering.xml
+++ b/docbook/reference/en/en-US/modules/clustering.xml
@@ -155,7 +155,7 @@
messages to the cluster. However, as there's no sensitive data sent there's not much that can be achieved.
For realms and users all that can be done is to send invalidation messages to make nodes load data from the
database more frequently. For user sessions it would be possible to modify existing user sessions, but creating
- new sessions would have no affect as they would not be linked to any access tokens. There's not to much that
+ new sessions would have no affect as they would not be linked to any access tokens. There's not too much that
can be achieved by modifying user sessions. For example it would be possible to prevent sessions from expiring,
by changing the creation time. However, it would for example have no effect adding additional permissions to the
sessions as these are rechecked against the user and application when the token is created or refreshed.
diff --git a/docbook/reference/en/en-US/modules/fuse-adapter.xml b/docbook/reference/en/en-US/modules/fuse-adapter.xml
new file mode 100644
index 0000000..22224c1
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/fuse-adapter.xml
@@ -0,0 +1,41 @@
+<section id="fuse-adapter">
+ <title>JBoss Fuse and Apache Karaf Adapter</title>
+ <para>
+ Currently Keycloak supports securing your web applications running inside <ulink url="http://www.jboss.org/products/fuse/overview/">JBoss Fuse</ulink>
+ or <ulink url="http://karaf.apache.org/">Apache Karaf</ulink> . It leverages <link linkend="jetty8-adapter">Jetty 8 adapter</link> as both JBoss Fuse 6.1
+ and Apache Karaf 3 are bundled with <ulink url="http://eclipse.org/jetty/">Jetty 8.1 server</ulink> under the covers and Jetty is used for running various kinds of web applications.
+ </para>
+ <para>
+ What is supported for Fuse/Karaf is:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Security for classic WAR applications deployed on Fuse/Karaf with <ulink url="https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War">Pax Web War Extender</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Security for servlets deployed on Fuse/Karaf as OSGI services with <ulink url="https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard">Pax Web Whiteboard Extender</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Security for <ulink url="http://camel.apache.org/">Apache Camel</ulink> Jetty endpoints running with
+ <ulink url="http://camel.apache.org/jetty.html">Camel Jetty</ulink> component.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Security for <ulink url="http://cxf.apache.org/">Apache CXF</ulink> endpoints running on their own separate
+ <ulink url="http://cxf.apache.org/docs/jetty-configuration.html">Jetty engine</ulink>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Security for <ulink url="http://cxf.apache.org/">Apache CXF</ulink> endpoints running on default engine provided by CXF servlet.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>The best place to start is look at Fuse demo bundled as part of Keycloak examples in directory <literal>examples/fuse</literal> .</para>
+</section>
\ No newline at end of file
docbook/reference/en/en-US/modules/jaas.xml 37(+37 -0)
diff --git a/docbook/reference/en/en-US/modules/jaas.xml b/docbook/reference/en/en-US/modules/jaas.xml
new file mode 100644
index 0000000..802dfcb
--- /dev/null
+++ b/docbook/reference/en/en-US/modules/jaas.xml
@@ -0,0 +1,37 @@
+<section id="jaas-adapter">
+ <title>JAAS plugin</title>
+ <para>
+ It's generally not needed to use JAAS for most of the applications, especially if they are HTTP based, but directly choose one of our adapters.
+ However some applications and systems may still rely on pure legacy JAAS solution. Keycloak provides couple of login modules
+ to help with such use cases. Some login modules provided by Keycloak are:
+ </para>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term>org.keycloak.adapters.jaas.DirectAccessGrantsLoginModule</term>
+ <listitem>
+ <para>
+ This login module allows to authenticate with username/password from Keycloak database. It's using
+ <link linkend="direct-access-grants">Direct Access Grants</link> Keycloak endpoint to validate on Keycloak side if provided username/password is valid.
+ It's useful especially for non-web based systems, which need to rely on JAAS and want to use Keycloak credentials, but can't use classic browser based
+ authentication flow due to their non-web nature. Example of such application could be messaging application or SSH system.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>org.keycloak.adapters.jaas.BearerTokenLoginModule</term>
+ <listitem>
+ <para>
+ This login module allows to authenticate with Keycloak access token passed to it through CallbackHandler as password.
+ It may be useful for example in case, when you have Keycloak access token from classic web based authentication flow
+ and your web application then needs to talk to external non-web based system, which rely on JAAS. For example to JMS/messaging system.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ Both login modules have single configuration property <literal>keycloak-config-file</literal> where you need to provide location of keycloak.json configuration file.
+ It could be either provided from filesystem or from classpath (in that case you may need value like <literal>classpath:/folder-on-classpath/keycloak.json</literal> ).
+ </para>
+</section>
\ No newline at end of file
diff --git a/docbook/reference/en/en-US/modules/per-realm-admin-permissions.xml b/docbook/reference/en/en-US/modules/per-realm-admin-permissions.xml
index 5080334..19f3863 100755
--- a/docbook/reference/en/en-US/modules/per-realm-admin-permissions.xml
+++ b/docbook/reference/en/en-US/modules/per-realm-admin-permissions.xml
@@ -4,7 +4,7 @@
Administering your realm through the <literal>master</literal> realm as discussed in <xref linkend="admin-permissions" /> may not always be
ideal or feasible. For example, maybe you have more than one admin application that manages various admin aspects of your organization
and you want to unify all these different "admin consoles" under one realm so you can do SSO between them. Keycloak allows you to
- grant realm admin privleges to users within that realm. These realm admins can participate in SSO for that realm and
+ grant realm admin privileges to users within that realm. These realm admins can participate in SSO for that realm and
visit a keycloak admin console instance that is dedicated solely for that realm by going to the url:
<literal>/{keycloak-root}/admin/{realm}/console</literal>
</para>
diff --git a/docbook/reference/en/en-US/modules/saml.xml b/docbook/reference/en/en-US/modules/saml.xml
index 5ba2e00..8cfd972 100755
--- a/docbook/reference/en/en-US/modules/saml.xml
+++ b/docbook/reference/en/en-US/modules/saml.xml
@@ -18,7 +18,7 @@
<term>Include AuthnStatement</term>
<listitem>
<para>
- SAML login responses may specify the authenticaiton method used (password, etc.) as well as
+ SAML login responses may specify the authentication method used (password, etc.) as well as
a timestamp of the login. Setting this to on will include that statement in the response document.
</para>
</listitem>
@@ -27,7 +27,7 @@
<term>Multi-valued Roles</term>
<listitem>
<para>
- If this switch is off, any user role mapings will have a corresponding attribute created for it.
+ If this switch is off, any user role mappings will have a corresponding attribute created for it.
If this switch is turn on, only one role attribute will be created, but it will have
multiple values within in.
</para>
@@ -82,7 +82,7 @@
<para>
By default, Keycloak will respond using the initial SAML binding of the original request. By turning
on this switch, you will force Keycloak to always respond using the SAML POST Binding even if the
- original request was a the Redirect binding.
+ original request was the Redirect binding.
</para>
</listitem>
</varlistentry>
diff --git a/docbook/reference/en/en-US/modules/server-installation.xml b/docbook/reference/en/en-US/modules/server-installation.xml
index 6ae4d47..3861a43 100755
--- a/docbook/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/reference/en/en-US/modules/server-installation.xml
@@ -66,7 +66,7 @@ keycloak-appliance-dist-all-&project.version;/
<literal>keycloak-war-dist-all-&project.version;.zip</literal>
contains
just the bits you need to install keycloak on your favorite web container. We currently only support
- installing it on top of an existing Wildfly 8, JBoss EAP 6.x or JBoss AS 7.1.1 distribution. We may in the
+ installing it on top of an existing Wildfly 8 or JBoss EAP 6.x distribution. We may in the
future provide directions on how to install it on another web container like Tomcat or Jetty. If anybody
in the community is interested in pulling this together, please contact us. Its mostly Maven pom work.
</para>
diff --git a/docbook/reference/en/en-US/modules/social-github.xml b/docbook/reference/en/en-US/modules/social-github.xml
index 1890f87..a4186e7 100755
--- a/docbook/reference/en/en-US/modules/social-github.xml
+++ b/docbook/reference/en/en-US/modules/social-github.xml
@@ -20,7 +20,7 @@
Copy <literal>Client ID</literal> and <literal>Client secret</literal> from the
<ulink url="https://github.com/settings/applications">GitHub Settings</ulink> into the settings
page in the Keycloak Admin Console as the <literal>Key</literal> and <literal>Secret</literal>. Then click
- <literal>Save</literal> in the Keycloak Admin Console to enable login with Google.
+ <literal>Save</literal> in the Keycloak Admin Console to enable login with GitHub.
</para>
</listitem>
</orderedlist>
diff --git a/docbook/reference/en/en-US/modules/themes.xml b/docbook/reference/en/en-US/modules/themes.xml
index af30453..3996b3a 100755
--- a/docbook/reference/en/en-US/modules/themes.xml
+++ b/docbook/reference/en/en-US/modules/themes.xml
@@ -25,7 +25,7 @@
<title>Configure theme</title>
<para>
All theme types, except welcome, is configured through <literal>Keycloak Admin Console</literal>. To change
- the theme used for a realm open the open the <literal>Keycloak Admin Console</literal>, select your realm
+ the theme used for a realm open the <literal>Keycloak Admin Console</literal>, select your realm
from the drop-down box in the top left corner. Under <literal>Settings</literal> click on <literal>Theme</literal>.
</para>
<para>
@@ -166,7 +166,7 @@
and <literal>org.keycloak.account.AccountProvider</literal>.
</para>
<para>
- Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal>to specify which provider should be used:
+ Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal> to specify which provider should be used:
<programlisting>
"account": {
"provider": "custom-provider"
@@ -182,7 +182,7 @@
and <literal>org.keycloak.login.LoginFormsProvider</literal> in <literal>forms/login-api</literal>.
</para>
<para>
- Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal>to specify which provider should be used:
+ Once you have deployed your account provider to Keycloak you need to configure <literal>keycloak-server.json</literal> to specify which provider should be used:
<programlisting>
"login": {
"provider": "custom-provider"
diff --git a/docbook/reference/en/en-US/modules/user-federation.xml b/docbook/reference/en/en-US/modules/user-federation.xml
index b08a58b..5eb1524 100755
--- a/docbook/reference/en/en-US/modules/user-federation.xml
+++ b/docbook/reference/en/en-US/modules/user-federation.xml
@@ -19,7 +19,7 @@
federation plugins may only import the username into Keycloak storage, others might import everything from name,
address, and phone number, to user role mappings. Some plugins might want to import credentials directly into
Keycloak storage and let Keycloak handle credential validation. Others might want to handle credential validation
- themselves. Thegoal of the Federation SPI is to support all of these scenarios.
+ themselves. The goal of the Federation SPI is to support all of these scenarios.
</para>
<section>
<title>LDAP and Active Directory Plugin</title>
@@ -76,7 +76,7 @@
<term>Display Name</term>
<listitem>
<para>
- Name used when this provider is referenced in the admin consle
+ Name used when this provider is referenced in the admin console
</para>
</listitem>
</varlistentry>
@@ -118,7 +118,7 @@
first import this LDAP user into Keycloak database and then authenticate against LDAP password.
</para>
<para>
- Thing is that Federation Provider import just requested users by default, so if you click to <literal>View all users</literal>
+ Federation Provider imports just requested users by default, so if you click to <literal>View all users</literal>
in Keycloak admin console, you will see just those LDAP users, which were already authenticated/requested by Keycloak.
</para>
<para>If you want to sync all LDAP users into Keycloak database, you may configure and enable Sync, which is in
@@ -160,7 +160,7 @@
<para>
Writing a User Federation Provider starts by implementing the <literal>UserFederationProvider</literal>
and <literal>UserFederationProviderFactory</literal> interfaces. Please see the Javadoc and example
- for complete details on on how to do this. Some important methods of note:
+ for complete details on how to do this. Some important methods of note:
getUserByUsername() and getUserByEmail() require that you query your federated storage and if the user exists
create and import the user into Keycloak storage. How much metadata you import is fully up to you. This
import is done by invoking methods on the object returned <literal>KeycloakSession.userStorage()</literal>
@@ -173,7 +173,7 @@
contain a file called <literal>org.keycloak.models.UserFederationProviderFactory</literal>
within the <literal>META-INF/services</literal> directory of the JAR. This file is a list
of fully qualified classnames of all implementations of <literal>UserFederationProviderFactory</literal>.
- This is how Keycloak discovers which providers have been deployment. Place the JAR in the
+ This is how Keycloak discovers which providers have been deployed. Place the JAR in the
keycloak WAR deployment in the <literal>WEB-INF/lib</literal> directory.
</para>
</section>
diff --git a/events/api/src/main/java/org/keycloak/events/Errors.java b/events/api/src/main/java/org/keycloak/events/Errors.java
index 2e75880..fa5d49b 100755
--- a/events/api/src/main/java/org/keycloak/events/Errors.java
+++ b/events/api/src/main/java/org/keycloak/events/Errors.java
@@ -41,4 +41,5 @@ public interface Errors {
String USER_SESSION_NOT_FOUND = "user_session_not_found";
String EMAIL_SEND_FAILED = "email_send_failed";
+ String INVALID_EMAIL = "invalid_email";
}
diff --git a/events/api/src/main/java/org/keycloak/events/EventType.java b/events/api/src/main/java/org/keycloak/events/EventType.java
index 681c87d..d292c4c 100755
--- a/events/api/src/main/java/org/keycloak/events/EventType.java
+++ b/events/api/src/main/java/org/keycloak/events/EventType.java
@@ -45,6 +45,8 @@ public enum EventType {
INVALID_SIGNATURE_ERROR,
REGISTER_NODE,
- UNREGISTER_NODE
+ UNREGISTER_NODE,
+ USER_INFO_REQUEST,
+ USER_INFO_REQUEST_ERROR
}
examples/cordova/www/index.html 25(+22 -3)
diff --git a/examples/cordova/www/index.html b/examples/cordova/www/index.html
index 9983ee8..a11ab24 100644
--- a/examples/cordova/www/index.html
+++ b/examples/cordova/www/index.html
@@ -18,9 +18,11 @@
document.getElementById('not-authenticated').style.display = 'none';
document.getElementById('subject').innerText = keycloak.subject;
- document.getElementById('username').innerText = keycloak.idToken.preferred_username;
+ document.getElementById('username').innerText = keycloak.idTokenParsed.preferred_username;
document.getElementById('tokenExpires').innerText = new Date(keycloak.tokenParsed.exp * 1000).toLocaleString();
document.getElementById('tokenRefreshExpires').innerText = new Date(keycloak.refreshTokenParsed.exp * 1000).toLocaleString();
+ document.getElementById('token').innerText = JSON.stringify(keycloak.tokenParsed, null, ' ');
+ document.getElementById('idToken').innerText = JSON.stringify(keycloak.idTokenParsed, null, ' ');
} else {
document.getElementById('authenticated').style.display = 'none';
document.getElementById('not-authenticated').style.display = 'block';
@@ -31,6 +33,15 @@
keycloak.init({ onLoad: 'check-sso' }).success(updateState);
}, false);
</script>
+ <style>
+ td {
+ vertical-align: top;
+ }
+
+ tr.odd td {
+ background-color: #eee;
+ }
+ </style>
</head>
<body>
<div id="authenticated" style="display: none;">
@@ -46,7 +57,7 @@
<td>Subject</td>
<td id="subject"></td>
</tr>
- <tr>
+ <tr class="odd">
<td>Username</td>
<td id="username"></td>
</tr>
@@ -54,10 +65,18 @@
<td>Token expires</td>
<td id="tokenExpires"></td>
</tr>
- <tr>
+ <tr class="odd">
<td>Refresh token expires</td>
<td id="tokenRefreshExpires"></td>
</tr>
+ <tr>
+ <td>Token</td>
+ <td><pre id="token"></pre></td>
+ </tr>
+ <tr class="odd">
+ <td>ID Token</td>
+ <td><pre id="idToken"></pre></td>
+ </tr>
</table>
</div>
</div>
diff --git a/examples/cors/angular-product-app/src/main/webapp/index.html b/examples/cors/angular-product-app/src/main/webapp/index.html
index 6cef8b9..b385fe3 100755
--- a/examples/cors/angular-product-app/src/main/webapp/index.html
+++ b/examples/cors/angular-product-app/src/main/webapp/index.html
@@ -81,6 +81,16 @@
</div>
</div>
<hr />
+ <div>
+ <h2><span>Server version</span></h2>
+ <button type="submit" data-ng-click="loadVersion()">Load version</button>
+
+ <div data-ng-show="version">
+ Keycloak version: {{version.version}} <br/>
+ Keycloak build time: {{version['build-time'] | date:'yyyy-MM-dd HH:mm:ss'}} <br/>
+ </div>
+ </div>
+ <hr />
</div>
</body>
</html>
diff --git a/examples/cors/angular-product-app/src/main/webapp/js/app.js b/examples/cors/angular-product-app/src/main/webapp/js/app.js
index 699644e..d6e9fd4 100755
--- a/examples/cors/angular-product-app/src/main/webapp/js/app.js
+++ b/examples/cors/angular-product-app/src/main/webapp/js/app.js
@@ -32,6 +32,9 @@ angular.element(document).ready(function ($http) {
module.controller('GlobalCtrl', function($scope, $http) {
$scope.products = [];
$scope.roles = [];
+ $scope.serverInfo = [];
+ $scope.realm = [];
+ $scope.version = [];
$scope.reloadData = function() {
$http.get("http://localhost-db:8080/cors-database/products").success(function(data) {
$scope.products = angular.fromJson(data);
@@ -72,6 +75,12 @@ module.controller('GlobalCtrl', function($scope, $http) {
});
};
+ $scope.loadVersion = function() {
+ $http.get("http://localhost-auth:8080/auth/version").success(function(data) {
+ $scope.version = angular.fromJson(data);
+ });
+ };
+
$scope.logout = logout;
});
diff --git a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
index c1ccc38..7b17e18 100755
--- a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
+++ b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
@@ -43,7 +43,7 @@ public class AdminClient {
HttpClient client = new HttpClientBuilder()
.disableTrustManager().build();
try {
- HttpGet get = new HttpGet(AdapterUtils.getOrigin(req.getRequestURL().toString(), session) + "/auth/admin/realms/demo/roles");
+ HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/auth/admin/realms/demo/roles");
get.addHeader("Authorization", "Bearer " + session.getTokenString());
try {
HttpResponse response = client.execute(get);
diff --git a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
index 0cb400f..3a0409b 100755
--- a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
+++ b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
@@ -7,8 +7,10 @@ import org.apache.http.client.methods.HttpGet;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.AdapterUtils;
import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.representations.IDToken;
import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.KeycloakUriBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@@ -50,7 +52,7 @@ public class CustomerDatabaseClient {
HttpClient client = new HttpClientBuilder()
.disableTrustManager().build();
try {
- HttpGet get = new HttpGet(AdapterUtils.getOrigin(req.getRequestURL().toString(), session) + "/database/customers");
+ HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/customers");
get.addHeader("Authorization", "Bearer " + session.getTokenString());
try {
HttpResponse response = client.execute(get);
diff --git a/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp b/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
index 04a54bb..2eb5e66 100755
--- a/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
+++ b/examples/demo-template/customer-app/src/main/webapp/customers/view.jsp
@@ -3,6 +3,7 @@
<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
<%@ page import="org.keycloak.representations.IDToken" %>
+<%@ page import="org.keycloak.representations.UserClaimSet" %>
<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
<%@ page session="false" %>
<html>
@@ -16,17 +17,18 @@
String acctUri = KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH)
.queryParam("referrer", "customer-portal").build("demo").toString();
IDToken idToken = CustomerDatabaseClient.getIDToken(request);
+ UserClaimSet claims = idToken.getUserClaimSet();
%>
<p>Goto: <a href="/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a
href="<%=acctUri%>">manage acct</a></p>
Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
</b> made this request.
<p><b>Caller IDToken values</b> (<i>You can specify what is returned in IDToken in the customer-portal claims page in the admin console</i>:</p>
-<p>Username: <%=idToken.getPreferredUsername()%></p>
-<p>Email: <%=idToken.getEmail()%></p>
-<p>Full Name: <%=idToken.getName()%></p>
-<p>First: <%=idToken.getGivenName()%></p>
-<p>Last: <%=idToken.getFamilyName()%></p>
+<p>Username: <%=claims.getPreferredUsername()%></p>
+<p>Email: <%=claims.getEmail()%></p>
+<p>Full Name: <%=claims.getName()%></p>
+<p>First: <%=claims.getGivenName()%></p>
+<p>Last: <%=claims.getFamilyName()%></p>
<h2>Customer Listing</h2>
<%
java.util.List<String> list = null;
diff --git a/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
index c8e9cf0..f259d0c 100755
--- a/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
+++ b/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -40,7 +40,7 @@ public class ProductDatabaseClient
HttpClient client = new HttpClientBuilder()
.disableTrustManager().build();
try {
- HttpGet get = new HttpGet(AdapterUtils.getOrigin(req.getRequestURL().toString(), session) + "/database/products");
+ HttpGet get = new HttpGet(AdapterUtils.getOriginForRestCalls(req.getRequestURL().toString(), session) + "/database/products");
get.addHeader("Authorization", "Bearer " + session.getTokenString());
try {
HttpResponse response = client.execute(get);
examples/demo-template/README.md 12(+7 -5)
diff --git a/examples/demo-template/README.md b/examples/demo-template/README.md
index 23ee8c6..ec5e02e 100755
--- a/examples/demo-template/README.md
+++ b/examples/demo-template/README.md
@@ -30,11 +30,9 @@ Step 1: Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
-a few steps you must follow.
-
-If using JBoss AS7, obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
-This installs the server using a WAR file. It is not needed on EAP6 and WildFly.
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
+a few steps you must follow. You need to obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
+This installs the server using a WAR file.
$ cd ${jboss.as7.home}/standalone
$ cp -r ${keycloak-war-dist-all}/deployments .
@@ -54,6 +52,10 @@ For JBoss AS 7.1.1:
$ cd ${as7.home}
$ unzip ${keycloak-war-dist-all}/adapters/keycloak-as7-adapter-dist.zip
+WARNING: Note that we don't officially support Keycloak auth-server running on JBoss AS 7.1.1. You can still test examples running on AS 7.1.1,
+but then you may need to do few additional changes in examples to point them into external Keycloak server running on WildFly or EAP 6.x.
+This is especially changing "auth-server-url" in keycloak.json files to be non-relative as examples and auth-server will run on different server!
+
Unzipping the adapter ZIP only installs the JAR files. You must also add the Keycloak Subsystem to the server's
configuration (standalone/configuration/standalone.xml).
diff --git a/examples/demo-template/third-party/src/main/webapp/pull_data.jsp b/examples/demo-template/third-party/src/main/webapp/pull_data.jsp
index 9f102b4..6ed0478 100755
--- a/examples/demo-template/third-party/src/main/webapp/pull_data.jsp
+++ b/examples/demo-template/third-party/src/main/webapp/pull_data.jsp
@@ -2,6 +2,7 @@
<%@ page import="org.keycloak.representations.AccessTokenResponse" %>
<%@ page import="org.keycloak.representations.IDToken" %>
<%@ page import="org.keycloak.servlet.ServletOAuthClient" %>
+<%@ page import="org.keycloak.representations.UserClaimSet" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ page session="false" %>
@@ -16,15 +17,16 @@
AccessTokenResponse tokenResponse = ProductDatabaseClient.getTokenResponse(request);
if (tokenResponse.getIdToken() != null) {
IDToken idToken = ServletOAuthClient.extractIdToken(tokenResponse.getIdToken());
+ UserClaimSet claimSet = idToken.getUserClaimSet();
out.println("<p><i>Change client claims in admin console to view personal info of user</i></p>");
- if (idToken.getPreferredUsername() != null) {
- out.println("<p>Username: " + idToken.getPreferredUsername() + "</p>");
+ if (claimSet.getPreferredUsername() != null) {
+ out.println("<p>Username: " + claimSet.getPreferredUsername() + "</p>");
}
- if (idToken.getName() != null) {
- out.println("<p>Full Name: " + idToken.getName() + "</p>");
+ if (claimSet.getName() != null) {
+ out.println("<p>Full Name: " + claimSet.getName() + "</p>");
}
- if (idToken.getEmail() != null) {
- out.println("<p>Email: " + idToken.getEmail() + "</p>");
+ if (claimSet.getEmail() != null) {
+ out.println("<p>Email: " + claimSet.getEmail() + "</p>");
}
}
list = ProductDatabaseClient.getProducts(request, tokenResponse.getToken());
examples/fuse/camel/pom.xml 79(+79 -0)
diff --git a/examples/fuse/camel/pom.xml b/examples/fuse/camel/pom.xml
new file mode 100644
index 0000000..51869c0
--- /dev/null
+++ b/examples/fuse/camel/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>camel-endpoint-example</artifactId>
+ <packaging>bundle</packaging>
+ <name>Camel endpoint example - Secured in Karaf/Fuse</name>
+ <description/>
+
+ <properties>
+ <camel.version>2.12.5</camel.version>
+ <keycloak.osgi.export>
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.eclipse.jetty.security;version="[8.1,10)",
+ org.eclipse.jetty.util.security;version="[8.1,10)",
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ <keycloak.osgi.private>
+ org.keycloak.example.*
+ </keycloak.osgi.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-core</artifactId>
+ <version>${camel.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-blueprint</artifactId>
+ <version>${camel.version}</version>
+ </dependency>
+ <dependency><groupId>org.apache.camel</groupId>
+ <artifactId>camel-jetty</artifactId>
+ <version>${camel.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Private-Package>${keycloak.osgi.private}</Private-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/examples/fuse/camel/src/main/java/org/keycloak/example/CamelHelloBean.java b/examples/fuse/camel/src/main/java/org/keycloak/example/CamelHelloBean.java
new file mode 100644
index 0000000..df5c472
--- /dev/null
+++ b/examples/fuse/camel/src/main/java/org/keycloak/example/CamelHelloBean.java
@@ -0,0 +1,15 @@
+package org.keycloak.example;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CamelHelloBean {
+
+ public String hello() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ return "Hello admin! It's " + sdf.format(new Date());
+ }
+}
diff --git a/examples/fuse/camel/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/examples/fuse/camel/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..0dc0fdd
--- /dev/null
+++ b/examples/fuse/camel/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:camel="http://camel.apache.org/schema/blueprint"
+ xsi:schemaLocation="
+ http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
+ http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
+
+ <bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <property name="realm" value="demo"/>
+ <property name="resource" value="admin-camel-endpoint"/>
+ <property name="realmKey" value="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"/>
+ <property name="bearerOnly" value="true"/>
+ <property name="sslRequired" value="EXTERNAL"/>
+ </bean>
+
+ <bean id="keycloakAuthenticator" class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <property name="adapterConfig" ref="kcAdapterConfig"/>
+ </bean>
+
+ <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
+ <property name="name" value="Customers"/>
+ <property name="roles">
+ <list>
+ <value>admin</value>
+ </list>
+ </property>
+ <property name="authenticate" value="true"/>
+ <property name="dataConstraint" value="0"/>
+ </bean>
+
+ <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
+ <property name="constraint" ref="constraint"/>
+ <property name="pathSpec" value="/*"/>
+ </bean>
+
+ <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
+ <property name="authenticator" ref="keycloakAuthenticator" />
+ <property name="constraintMappings">
+ <list>
+ <ref component-id="constraintMapping" />
+ </list>
+ </property>
+ <property name="authMethod" value="BASIC"/>
+ <property name="realmName" value="does-not-matter"/>
+ </bean>
+
+ <bean id="sessionHandler" class="org.keycloak.adapters.jetty.core.WrappingSessionHandler">
+ <property name="handler" ref="securityHandler" />
+ </bean>
+
+ <bean id="helloBean" class="org.keycloak.example.CamelHelloBean" />
+
+ <camelContext id="blueprintContext"
+ trace="false"
+ xmlns="http://camel.apache.org/schema/blueprint">
+ <route id="httpBridge">
+ <from uri="jetty:http://0.0.0.0:8383/admin-camel-endpoint?handlers=sessionHandler&matchOnUriPrefix=true" />
+ <setBody>
+ <method ref="helloBean" method="hello"/>
+ </setBody>
+ <log message="The message from camel endpoint contains ${body}"/>
+ <to uri="mock:result"/>
+ </route>
+ </camelContext>
+
+</blueprint>
\ No newline at end of file
examples/fuse/customer-app-fuse/pom.xml 121(+121 -0)
diff --git a/examples/fuse/customer-app-fuse/pom.xml b/examples/fuse/customer-app-fuse/pom.xml
new file mode 100644
index 0000000..88fedcc
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/pom.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>customer-portal-fuse-example</artifactId>
+ <packaging>war</packaging>
+ <name>Customer Portal - Secured in Karaf/Fuse</name>
+ <description/>
+
+ <properties>
+ <keycloak.osgi.export>
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.apache.http.*;version=${keycloak.apache.httpcomponents.version},
+ javax.servlet.*;version="[2.5,4)",
+ org.keycloak.adapters.jetty;version="${project.version}",
+ org.keycloak.adapters;version="${project.version}",
+ org.keycloak.constants;version="${project.version}",
+ org.keycloak.util;version="${project.version}",
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ <keycloak.osgi.private>
+ org.keycloak.example.*
+ </keycloak.osgi.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${keycloak.apache.httpcomponents.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <finalName>customer-portal-fuse</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${basedir}/target/classes/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <supportedProjectTypes>
+ <supportedProjectType>war</supportedProjectType>
+ </supportedProjectTypes>
+ <instructions>
+ <Webapp-Context>customer-portal</Webapp-Context>
+ <Web-ContextPath>customer-portal</Web-ContextPath>
+ <Embed-Directory>WEB-INF/lib</Embed-Directory>
+ <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Private-Package>${keycloak.osgi.private}</Private-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CamelClient.java b/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CamelClient.java
new file mode 100644
index 0000000..9ddb8f1
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CamelClient.java
@@ -0,0 +1,74 @@
+package org.keycloak.example;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.HttpClientBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CamelClient {
+
+ public static String sendRequest(HttpServletRequest req) throws CxfRsClient.Failure {
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+
+ HttpClient client = new HttpClientBuilder()
+ .disableTrustManager().build();
+ try {
+ HttpGet get = new HttpGet("http://localhost:8383/admin-camel-endpoint");
+ get.addHeader("Authorization", "Bearer " + session.getTokenString());
+ try {
+ HttpResponse response = client.execute(get);
+ if (response.getStatusLine().getStatusCode() != 200) {
+ return "There was a failure processing request. You either didn't configure Keycloak properly or you don't have enought permission? Status code is "
+ + response.getStatusLine().getStatusCode();
+ }
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ return getStringFromInputStream(is);
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ client.getConnectionManager().shutdown();
+ }
+ }
+
+ private static String getStringFromInputStream(InputStream is) {
+ BufferedReader br = null;
+ StringBuilder sb = new StringBuilder();
+ String line;
+ try {
+ br = new BufferedReader(new InputStreamReader(is));
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return sb.toString();
+
+ }
+}
diff --git a/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CxfRsClient.java b/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CxfRsClient.java
new file mode 100644
index 0000000..4d64429
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/java/org/keycloak/example/CxfRsClient.java
@@ -0,0 +1,75 @@
+package org.keycloak.example;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.representations.IDToken;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.UriUtils;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CxfRsClient {
+
+ static class TypedList extends ArrayList<String> {
+ }
+
+ public static class Failure extends Exception {
+ private int status;
+
+ public Failure(int status) {
+ this.status = status;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+ }
+
+ public static IDToken getIDToken(HttpServletRequest req) {
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+ return session.getIdToken();
+
+ }
+
+ public static List<String> getCustomers(HttpServletRequest req) throws Failure {
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+
+ HttpClient client = new HttpClientBuilder()
+ .disableTrustManager().build();
+ try {
+ HttpGet get = new HttpGet(UriUtils.getOrigin(req.getRequestURL().toString()) + "/cxf/customerservice/customers");
+ get.addHeader("Authorization", "Bearer " + session.getTokenString());
+ try {
+ HttpResponse response = client.execute(get);
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new Failure(response.getStatusLine().getStatusCode());
+ }
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ try {
+ return JsonSerialization.readValue(is, TypedList.class);
+ } finally {
+ is.close();
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } finally {
+ client.getConnectionManager().shutdown();
+ }
+ }
+
+}
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/customers/camel.jsp b/examples/fuse/customer-app-fuse/src/main/webapp/customers/camel.jsp
new file mode 100755
index 0000000..1d29927
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/customers/camel.jsp
@@ -0,0 +1,15 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.example.CamelClient" %>
+<%@ page import="org.keycloak.representations.IDToken" %>
+<html>
+ <head>
+ <title>Camel page</title>
+ </head>
+ <body bgcolor="#E3F6CE">
+ <p>You will receive info from camel endpoint. Endpoint is accessible just for admin user</p>
+ <p>Response from camel: <b><%= CamelClient.sendRequest(request) %></b> </p>
+ <br><br>
+ </body>
+</html>
\ No newline at end of file
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/customers/cxf-ws.jsp b/examples/fuse/customer-app-fuse/src/main/webapp/customers/cxf-ws.jsp
new file mode 100755
index 0000000..45c5dcb
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/customers/cxf-ws.jsp
@@ -0,0 +1,50 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.example.CxfRsClient" %>
+<%@ page import="org.keycloak.representations.IDToken" %>
+<%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
+<%@ page session="false" %>
+<html>
+<head>
+ <title>Customer View Page</title>
+</head>
+<body bgcolor="#E3F6CE">
+<%
+ String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+ .queryParam("redirect_uri", "http://localhost:8181/customer-portal").build("demo").toString();
+ String acctUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH)
+ .queryParam("referrer", "customer-portal").build("demo").toString();
+ IDToken idToken = CxfRsClient.getIDToken(request);
+%>
+<p>Goto: <a href="/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a
+ href="<%=acctUri%>">manage acct</a></p>
+Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
+</b> made this request.
+<p><b>Caller IDToken values</b> (<i>You can specify what is returned in IDToken in the customer-portal claims page in the admin console</i>:</p>
+<p>Username: <%=idToken.getPreferredUsername()%></p>
+<p>Email: <%=idToken.getEmail()%></p>
+<p>Full Name: <%=idToken.getName()%></p>
+<p>First: <%=idToken.getGivenName()%></p>
+<p>Last: <%=idToken.getFamilyName()%></p>
+<h2>Customer Listing</h2>
+<%
+ java.util.List<String> list = null;
+ try {
+ list = CxfRsClient.getCustomers(request);
+ } catch (CxfRsClient.Failure failure) {
+ out.println("There was a failure processing request. You either didn't configure Keycloak properly, or maybe" +
+ "you just forgot to secure the cxf ws service?");
+ out.println("Status from cxf ws service invocation was: " + failure.getStatus());
+ return;
+ }
+ for (String cust : list) {
+ out.print("<p>");
+ out.print(cust);
+ out.println("</p>");
+
+ }
+%>
+<br><br>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/index.html b/examples/fuse/customer-app-fuse/src/main/webapp/index.html
new file mode 100755
index 0000000..3da0d42
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/index.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Customer portal on Karaf/Fuse</title>
+ </head>
+ <body bgcolor="#E3F6CE">
+ <h1>Customer Portal</h1>
+
+ <p><a href="customers/cxf-ws.jsp">Customer Listing - CXF WS endpoint</a></p>
+
+ <p><a href="customers/camel.jsp">Admin Interface - Apache Camel endpoint</a></p>
+
+ </body>
+</html>
\ No newline at end of file
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/jetty-web.xml b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..e3d87a2
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/jetty-web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/keycloak.json b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/keycloak.json
new file mode 100755
index 0000000..b5d6b30
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm": "demo",
+ "resource": "customer-portal",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8080/auth",
+ "ssl-required" : "external",
+ "credentials": {
+ "secret": "password"
+ }
+}
diff --git a/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/web.xml b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..6fb7590
--- /dev/null
+++ b/examples/fuse/customer-app-fuse/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+
+ <module-name>customer-portal</module-name>
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Customers</web-resource-name>
+ <url-pattern>/customers/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>user</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>does-not-matter</realm-name>
+ </login-config>
+
+ <security-role>
+ <role-name>admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>user</role-name>
+ </security-role>
+</web-app>
examples/fuse/cxf-jaxrs/pom.xml 86(+86 -0)
diff --git a/examples/fuse/cxf-jaxrs/pom.xml b/examples/fuse/cxf-jaxrs/pom.xml
new file mode 100644
index 0000000..b6a6237
--- /dev/null
+++ b/examples/fuse/cxf-jaxrs/pom.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>cxf-jaxrs-example</artifactId>
+ <packaging>bundle</packaging>
+ <name>CXF JAXRS Example - Secured in Karaf/Fuse</name>
+
+ <properties>
+ <cxf.version>2.7.14</cxf.version>
+ <keycloak.osgi.export>
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ META-INF.cxf,
+ META-INF.cxf.osgi,
+ org.apache.cxf.bus,
+ org.apache.cxf.bus.spring,
+ org.apache.cxf.bus.resource,
+ org.apache.cxf.resource,
+ org.apache.cxf.jaxrs,
+ org.apache.cxf.transport.http,
+ org.codehaus.jackson.jaxrs;version="${jackson.version}",
+ org.keycloak.adapters.jetty;version="${project.version}",
+ org.keycloak.adapters;version="${project.version}",
+ *
+ </keycloak.osgi.import>
+ <keycloak.osgi.private>
+ org.keycloak.example.rs.*
+ </keycloak.osgi.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http-jetty</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Private-Package>${keycloak.osgi.private}</Private-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/examples/fuse/cxf-jaxrs/src/main/java/org/keycloak/example/rs/CxfCustomerService.java b/examples/fuse/cxf-jaxrs/src/main/java/org/keycloak/example/rs/CxfCustomerService.java
new file mode 100644
index 0000000..c761556
--- /dev/null
+++ b/examples/fuse/cxf-jaxrs/src/main/java/org/keycloak/example/rs/CxfCustomerService.java
@@ -0,0 +1,30 @@
+package org.keycloak.example.rs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Path("/customers")
+public class CxfCustomerService {
+
+ @GET
+ @Produces("application/json")
+ public List<String> getCustomers() {
+ ArrayList<String> rtn = new ArrayList<String>();
+ rtn.add("Bill Burke");
+ rtn.add("Stian Thorgersen");
+ rtn.add("Stan Silvert");
+ rtn.add("Gabriel Cardoso");
+ rtn.add("Viliam Rockai");
+ rtn.add("Marek Posolda");
+ rtn.add("Boleslaw Dawidowicz");
+ return rtn;
+ }
+}
diff --git a/examples/fuse/cxf-jaxrs/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/examples/fuse/cxf-jaxrs/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..1515416
--- /dev/null
+++ b/examples/fuse/cxf-jaxrs/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
+ xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
+ xsi:schemaLocation="
+ http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
+ http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
+ http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+ <!-- JAXRS Application -->
+
+ <bean id="customerBean" class="org.keycloak.example.rs.CxfCustomerService" />
+
+ <jaxrs:server id="cxfJaxrsServer" address="/customerservice">
+ <jaxrs:providers>
+ <!--<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider" />-->
+ <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
+ </jaxrs:providers>
+ <jaxrs:serviceBeans>
+ <ref component-id="customerBean" />
+ </jaxrs:serviceBeans>
+ </jaxrs:server>
+
+ <!-- Securing of whole /cxf context by unregister default cxf servlet from paxweb and re-register with applied security constraints -->
+
+ <cm:property-placeholder persistent-id="org.apache.cxf.osgi" id="cxfOsgiPropertiesKCSecured">
+ <cm:default-properties>
+ <cm:property name="org.apache.cxf.servlet.context" value="/cxf"/>
+ <cm:property name="org.apache.cxf.servlet.name" value="cxf-osgi-transport-servlet"/>
+ <cm:property name="org.apache.cxf.servlet.hide-service-list-page" value="false"/>
+ <cm:property name="org.apache.cxf.servlet.disable-address-updates" value="false"/>
+ <cm:property name="org.apache.cxf.servlet.base-address" value=""/>
+ <cm:property name="org.apache.cxf.servlet.service-list-path" value=""/>
+ <cm:property name="org.apache.cxf.servlet.static-resources-list" value=""/>
+ <cm:property name="org.apache.cxf.servlet.redirects-list" value=""/>
+ <cm:property name="org.apache.cxf.servlet.redirect-servlet-name" value=""/>
+ <cm:property name="org.apache.cxf.servlet.redirect-servlet-path" value=""/>
+ <cm:property name="org.apache.cxf.servlet.service-list-all-contexts" value=""/>
+ <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate" value="false"/>
+ <cm:property name="org.apache.cxf.servlet.service-list-page-authenticate-realm" value="karaf"/>
+ </cm:default-properties>
+ </cm:property-placeholder>
+
+ <bean id="cxfConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
+ <property name="constraint">
+ <bean class="org.eclipse.jetty.util.security.Constraint">
+ <property name="name" value="cst1"/>
+ <property name="roles">
+ <list>
+ <value>user</value>
+ </list>
+ </property>
+ <property name="authenticate" value="true"/>
+ <property name="dataConstraint" value="0"/>
+ </bean>
+ </property>
+ <property name="pathSpec" value="/cxf/*"/>
+ </bean>
+
+ <bean id="cxfKeycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.PaxWebIntegrationService"
+ init-method="start" destroy-method="stop">
+ <property name="bundleContext" ref="blueprintBundleContext" />
+ <property name="jettyWebXmlLocation" value="/WEB-INF/jetty-web.xml" />
+ <property name="constraintMappings">
+ <list>
+ <ref component-id="cxfConstraintMapping" />
+ </list>
+ </property>
+ </bean>
+
+ <bean id="defaultCxfUnregistration" class="org.keycloak.adapters.osgi.ServletUnregistrationService"
+ init-method="start" destroy-method="stop">
+ <property name="bundleContext" ref="blueprintBundleContext" />
+ <property name="servletReference">
+ <reference interface="javax.servlet.Servlet" component-name="osgiServlet" />
+ </property>
+ </bean>
+
+ <bean id="osgiServletKCSecured" class="org.apache.cxf.transport.servlet.CXFNonSpringServlet" depends-on="cxfKeycloakPaxWebIntegration defaultCxfUnregistration">
+ <argument>
+ <reference interface="org.apache.cxf.transport.http.DestinationRegistry" timeout="5000"/>
+ </argument>
+ <argument value="false"/>
+ </bean>
+
+ <service ref="osgiServletKCSecured" interface="javax.servlet.Servlet">
+ <service-properties>
+ <entry key="alias" value="${org.apache.cxf.servlet.context}"/>
+ <entry key="servlet-name" value="${org.apache.cxf.servlet.name}"/>
+ <entry key="hide-service-list-page" value="${org.apache.cxf.servlet.hide-service-list-page}"/>
+ <entry key="disable-address-updates" value="${org.apache.cxf.servlet.disable-address-updates}"/>
+ <entry key="base-address" value="${org.apache.cxf.servlet.base-address}"/>
+ <entry key="service-list-path" value="${org.apache.cxf.servlet.service-list-path}"/>
+ <entry key="static-resources-list" value="${org.apache.cxf.servlet.static-resources-list}"/>
+ <entry key="redirects-list" value="${org.apache.cxf.servlet.redirects-list}"/>
+ <entry key="redirect-servlet-name" value="${org.apache.cxf.servlet.redirect-servlet-name}"/>
+ <entry key="redirect-servlet-path" value="${org.apache.cxf.servlet.redirect-servlet-path}"/>
+ <entry key="service-list-all-contexts" value="${org.apache.cxf.servlet.service-list-all-contexts}"/>
+ <entry key="service-list-page-authenticate" value="${org.apache.cxf.servlet.service-list-page-authenticate}"/>
+ <entry key="service-list-page-authenticate-realm" value="${org.apache.cxf.servlet.service-list-page-authenticate-realm}"/>
+ </service-properties>
+ </service>
+
+
+</blueprint>
\ No newline at end of file
diff --git a/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/jetty-web.xml b/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..e3d87a2
--- /dev/null
+++ b/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/jetty-web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/keycloak.json b/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/keycloak.json
new file mode 100644
index 0000000..f5d7e1a
--- /dev/null
+++ b/examples/fuse/cxf-jaxrs/src/main/resources/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm": "demo",
+ "resource": "builtin-cxf-app",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8080/auth",
+ "ssl-required" : "external",
+ "credentials": {
+ "secret": "password"
+ }
+}
examples/fuse/cxf-jaxws/pom.xml 107(+107 -0)
diff --git a/examples/fuse/cxf-jaxws/pom.xml b/examples/fuse/cxf-jaxws/pom.xml
new file mode 100644
index 0000000..abb2e01
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>cxf-jaxws-example</artifactId>
+ <packaging>bundle</packaging>
+ <name>CXF JAXWS Example - Secured in Karaf/Fuse</name>
+ <description/>
+
+ <properties>
+ <cxf.version>2.7.14</cxf.version>
+ <keycloak.osgi.export>
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ javax.jws;resolution:=optional,
+ javax.wsdl,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ javax.xml.namespace,
+ javax.xml.ws,
+ META-INF.cxf,
+ META-INF.cxf.osgi,
+ org.apache.cxf.bus,
+ org.apache.cxf.bus.spring,
+ org.apache.cxf.bus.resource,
+ org.apache.cxf.configuration.spring,
+ org.apache.cxf.resource,
+ org.apache.cxf.jaxws,
+ org.apache.cxf.transport.http,
+ org.springframework.beans.factory.config,
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ <keycloak.osgi.private>
+ org.keycloak.example.ws.*
+ </keycloak.osgi.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-ws-metadata_2.0_spec</artifactId>
+ <version>1.1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jaxws_2.2_spec</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <version>2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxws</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-transports-http-jetty</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Private-Package>${keycloak.osgi.private}</Private-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/Person.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/Person.java
new file mode 100644
index 0000000..24926e0
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/Person.java
@@ -0,0 +1,27 @@
+package org.keycloak.example.ws;
+
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebService;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.ws.RequestWrapper;
+import javax.xml.ws.ResponseWrapper;
+
+import org.keycloak.example.ws.types.ObjectFactory;
+
+@WebService
+@XmlSeeAlso({ObjectFactory.class})
+public interface Person {
+
+ @RequestWrapper(localName = "GetPerson", className = "GetPerson")
+ @ResponseWrapper(localName = "GetPersonResponse", className = "GetPersonResponse")
+ @WebMethod(operationName = "GetPerson")
+ public void getPerson(
+ @WebParam(mode = WebParam.Mode.INOUT, name = "personId")
+ javax.xml.ws.Holder<String> personId,
+ @WebParam(mode = WebParam.Mode.OUT, name = "ssn")
+ javax.xml.ws.Holder<String> ssn,
+ @WebParam(mode = WebParam.Mode.OUT, name = "name")
+ javax.xml.ws.Holder<String> name
+ ) throws UnknownPersonFault;
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/PersonImpl.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/PersonImpl.java
new file mode 100644
index 0000000..dcaf738
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/PersonImpl.java
@@ -0,0 +1,22 @@
+package org.keycloak.example.ws;
+
+import javax.jws.WebService;
+import javax.xml.ws.Holder;
+
+@WebService(serviceName = "PersonService", endpointInterface = "org.keycloak.example.ws.Person")
+public class PersonImpl implements Person {
+
+ public void getPerson(Holder<String> personId, Holder<String> ssn, Holder<String> name)
+ throws UnknownPersonFault
+ {
+ if (personId.value == null || personId.value.length() == 0) {
+ org.keycloak.example.ws.types.UnknownPersonFault fault = new org.keycloak.example.ws.types.UnknownPersonFault();
+ fault.setPersonId(personId.value);
+ throw new UnknownPersonFault(null,fault);
+ } else {
+ name.value = "John Doe";
+ ssn.value = "123-456-7890";
+ }
+ }
+
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPerson.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPerson.java
new file mode 100644
index 0000000..2101b1b
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPerson.java
@@ -0,0 +1,64 @@
+
+package org.keycloak.example.ws.types;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "personId"
+})
+@XmlRootElement(name = "GetPerson")
+public class GetPerson {
+
+ @XmlElement(required = true)
+ protected String personId;
+
+ /**
+ * Gets the value of the personId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getPersonId() {
+ return personId;
+ }
+
+ /**
+ * Sets the value of the personId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setPersonId(String value) {
+ this.personId = value;
+ }
+
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPersonResponse.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPersonResponse.java
new file mode 100644
index 0000000..fac5e6f
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/GetPersonResponse.java
@@ -0,0 +1,120 @@
+
+package org.keycloak.example.ws.types;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="ssn" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "personId",
+ "ssn",
+ "name"
+})
+@XmlRootElement(name = "GetPersonResponse")
+public class GetPersonResponse {
+
+ @XmlElement(required = true)
+ protected String personId;
+ @XmlElement(required = true)
+ protected String ssn;
+ @XmlElement(required = true)
+ protected String name;
+
+ /**
+ * Gets the value of the personId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getPersonId() {
+ return personId;
+ }
+
+ /**
+ * Sets the value of the personId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setPersonId(String value) {
+ this.personId = value;
+ }
+
+ /**
+ * Gets the value of the ssn property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getSsn() {
+ return ssn;
+ }
+
+ /**
+ * Sets the value of the ssn property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setSsn(String value) {
+ this.ssn = value;
+ }
+
+ /**
+ * Gets the value of the name property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the value of the name property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setName(String value) {
+ this.name = value;
+ }
+
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/ObjectFactory.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/ObjectFactory.java
new file mode 100644
index 0000000..dd2e74d
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/ObjectFactory.java
@@ -0,0 +1,56 @@
+
+package org.keycloak.example.ws.types;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.apache.servicemix.samples.wsdl_first.types package.
+ * <p>An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.apache.servicemix.samples.wsdl_first.types
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link GetPersonResponse }
+ *
+ */
+ public GetPersonResponse createGetPersonResponse() {
+ return new GetPersonResponse();
+ }
+
+ /**
+ * Create an instance of {@link GetPerson }
+ *
+ */
+ public GetPerson createGetPerson() {
+ return new GetPerson();
+ }
+
+ /**
+ * Create an instance of {@link UnknownPersonFault }
+ *
+ */
+ public UnknownPersonFault createUnknownPersonFault() {
+ return new UnknownPersonFault();
+ }
+
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/package-info.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/package-info.java
new file mode 100644
index 0000000..877c2df
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/package-info.java
@@ -0,0 +1 @@
+package org.keycloak.example.ws.types;
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/UnknownPersonFault.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/UnknownPersonFault.java
new file mode 100644
index 0000000..ba40a42
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/types/UnknownPersonFault.java
@@ -0,0 +1,64 @@
+
+package org.keycloak.example.ws.types;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "personId"
+})
+@XmlRootElement(name = "UnknownPersonFault")
+public class UnknownPersonFault {
+
+ @XmlElement(required = true)
+ protected String personId;
+
+ /**
+ * Gets the value of the personId property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getPersonId() {
+ return personId;
+ }
+
+ /**
+ * Sets the value of the personId property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setPersonId(String value) {
+ this.personId = value;
+ }
+
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownPersonFault.java b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownPersonFault.java
new file mode 100644
index 0000000..f013657
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/java/org/keycloak/example/ws/UnknownPersonFault.java
@@ -0,0 +1,36 @@
+package org.keycloak.example.ws;
+
+import javax.xml.ws.WebFault;
+
+@WebFault(name = "UnknownPersonFault")
+public class UnknownPersonFault extends Exception {
+ public static final long serialVersionUID = 20081110144906L;
+
+ private org.keycloak.example.ws.types.UnknownPersonFault unknownPersonFault;
+
+ public UnknownPersonFault() {
+ super();
+ }
+
+ public UnknownPersonFault(String message) {
+ super(message);
+ }
+
+ public UnknownPersonFault(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public UnknownPersonFault(String message, org.keycloak.example.ws.types.UnknownPersonFault unknownPersonFault) {
+ super(message);
+ this.unknownPersonFault = unknownPersonFault;
+ }
+
+ public UnknownPersonFault(String message, org.keycloak.example.ws.types.UnknownPersonFault unknownPersonFault, Throwable cause) {
+ super(message, cause);
+ this.unknownPersonFault = unknownPersonFault;
+ }
+
+ public org.keycloak.example.ws.types.UnknownPersonFault getFaultInfo() {
+ return this.unknownPersonFault;
+ }
+}
diff --git a/examples/fuse/cxf-jaxws/src/main/resources/META-INF/spring/beans.xml b/examples/fuse/cxf-jaxws/src/main/resources/META-INF/spring/beans.xml
new file mode 100644
index 0000000..57a7eee
--- /dev/null
+++ b/examples/fuse/cxf-jaxws/src/main/resources/META-INF/spring/beans.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated by Apache ServiceMix Archetype -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:jaxws="http://cxf.apache.org/jaxws"
+ xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
+ http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
+ http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd">
+
+ <import resource="classpath:META-INF/cxf/cxf.xml" />
+
+ <bean id="kcAdapterConfig" class="org.keycloak.representations.adapters.config.AdapterConfig">
+ <property name="realm" value="demo"/>
+ <property name="resource" value="custom-cxf-endpoint"/>
+ <property name="realmKey" value="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"/>
+ <property name="bearerOnly" value="true"/>
+ <property name="sslRequired" value="EXTERNAL"/>
+ </bean>
+
+ <bean id="keycloakAuthenticator" class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ <property name="adapterConfig">
+ <ref local="kcAdapterConfig" />
+ </property>
+ </bean>
+
+ <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">
+ <property name="name" value="Customers"/>
+ <property name="roles">
+ <list>
+ <value>user</value>
+ </list>
+ </property>
+ <property name="authenticate" value="true"/>
+ <property name="dataConstraint" value="0"/>
+ </bean>
+
+ <bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
+ <property name="constraint" ref="constraint"/>
+ <property name="pathSpec" value="/*"/>
+ </bean>
+
+ <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">
+ <property name="authenticator" ref="keycloakAuthenticator" />
+ <property name="constraintMappings">
+ <list>
+ <ref local="constraintMapping" />
+ </list>
+ </property>
+ <property name="authMethod" value="BASIC"/>
+ <property name="realmName" value="does-not-matter"/>
+ </bean>
+
+ <httpj:engine-factory bus="cxf" id="kc-cxf-endpoint">
+ <httpj:engine port="8282">
+ <httpj:handlers>
+ <ref local="securityHandler" />
+ </httpj:handlers>
+ <httpj:sessionSupport>true</httpj:sessionSupport>
+ </httpj:engine>
+ </httpj:engine-factory>
+
+ <jaxws:endpoint
+ implementor="org.keycloak.example.ws.PersonImpl"
+ address="http://localhost:8282/PersonServiceCF" depends-on="kc-cxf-endpoint"/>
+
+</beans>
\ No newline at end of file
examples/fuse/features/pom.xml 62(+62 -0)
diff --git a/examples/fuse/features/pom.xml b/examples/fuse/features/pom.xml
new file mode 100644
index 0000000..e6e8bfc
--- /dev/null
+++ b/examples/fuse/features/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>keycloak-fuse-example-features</artifactId>
+ <name>Keycloak Fuse Example - Features</name>
+ <description/>
+
+ <build>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ <filtering>true</filtering>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>filter</id>
+ <phase>generate-resources</phase>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>target/classes/features.xml</file>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/examples/fuse/features/src/main/resources/features.xml b/examples/fuse/features/src/main/resources/features.xml
new file mode 100644
index 0000000..f888574
--- /dev/null
+++ b/examples/fuse/features/src/main/resources/features.xml
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="keycloak-${project.version}">
+
+ <feature name="keycloak-fuse-example" version="${project.version}">
+ <details>The keycloak fuse example</details>
+ <feature>war</feature>
+ <feature>camel</feature>
+ <feature>camel-jetty</feature>
+ <feature>cxf</feature>
+ <feature>keycloak</feature>
+ <bundle dependency="true">mvn:org.codehaus.jackson/jackson-jaxrs/${jackson.version}</bundle>
+ <bundle>mvn:org.keycloak.example.demo/product-portal-fuse-example/${project.version}</bundle>
+ <bundle>mvn:org.keycloak.example.demo/customer-portal-fuse-example/${project.version}/war</bundle>
+ <bundle>mvn:org.keycloak.example.demo/camel-endpoint-example/${project.version}</bundle>
+ <bundle>mvn:org.keycloak.example.demo/cxf-jaxws-example/${project.version}</bundle>
+ <bundle>mvn:org.keycloak.example.demo/cxf-jaxrs-example/${project.version}</bundle>
+ </feature>
+
+</features>
\ No newline at end of file
examples/fuse/pom.xml 37(+37 -0)
diff --git a/examples/fuse/pom.xml b/examples/fuse/pom.xml
new file mode 100644
index 0000000..dba65c3
--- /dev/null
+++ b/examples/fuse/pom.xml
@@ -0,0 +1,37 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <name>Fuse examples</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>fuse-pom</artifactId>
+ <packaging>pom</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <modules>
+ <module>customer-app-fuse</module>
+ <module>product-app-fuse</module>
+ <module>cxf-jaxrs</module>
+ <module>cxf-jaxws</module>
+ <module>camel</module>
+ <module>features</module>
+ </modules>
+
+</project>
\ No newline at end of file
examples/fuse/product-app-fuse/pom.xml 83(+83 -0)
diff --git a/examples/fuse/product-app-fuse/pom.xml b/examples/fuse/product-app-fuse/pom.xml
new file mode 100644
index 0000000..fffd656
--- /dev/null
+++ b/examples/fuse/product-app-fuse/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>product-portal-fuse-example</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Product Portal - Secured in Karaf/Fuse</name>
+ <description/>
+
+ <properties>
+ <keycloak.osgi.export>
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.eclipse.jetty.security;version="[8.1,10)",
+ org.eclipse.jetty.util.security;version="[8.1,10)",
+ org.keycloak.adapters.jetty;version="${project.version}",
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ <keycloak.osgi.private>
+ org.keycloak.example.*
+ </keycloak.osgi.private>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Dependency for jaxws client to allow sending request to jaxws endpoint provided by cxf-jaxws-example -->
+ <dependency>
+ <groupId>org.keycloak.example.demo</groupId>
+ <artifactId>cxf-jaxws-example</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Private-Package>${keycloak.osgi.private}</Private-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ <Require-Bundle>org.apache.cxf.bundle</Require-Bundle>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/examples/fuse/product-app-fuse/src/main/java/org/keycloak/example/ProductPortalServlet.java b/examples/fuse/product-app-fuse/src/main/java/org/keycloak/example/ProductPortalServlet.java
new file mode 100644
index 0000000..85ecc42
--- /dev/null
+++ b/examples/fuse/product-app-fuse/src/main/java/org/keycloak/example/ProductPortalServlet.java
@@ -0,0 +1,95 @@
+package org.keycloak.example;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.xml.ws.WebServiceException;
+
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.frontend.ClientProxy;
+import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
+import org.apache.cxf.message.Message;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.constants.ServiceUrlConstants;
+import org.keycloak.example.ws.Person;
+import org.keycloak.example.ws.UnknownPersonFault;
+import org.keycloak.util.KeycloakUriBuilder;
+
+/**
+ * Servlet for receiving informations about products from backend JAXWS service. Actually it's about "persons" not "products" :)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ProductPortalServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.setContentType("text/html");
+
+ // Send jaxws request
+ PrintWriter out = resp.getWriter();
+ out.println("<html><head><title>Product Portal Page</title></head><body>");
+
+ String logoutUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+ .queryParam("redirect_uri", "http://localhost:8181/product-portal").build("demo").toString();
+ String acctUri = KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH)
+ .queryParam("referrer", "product-portal").build("demo").toString();
+
+ out.println("<p>Goto: <a href=\"/customer-portal\">customers</a> | <a href=\"" + logoutUri + "\">logout</a> | <a href=\"" + acctUri + "\">manage acct</a></p>");
+ out.println("Servlet User Principal <b>" + req.getUserPrincipal() + "</b> made this request.");
+
+ String unsecuredWsClientResponse = sendWsReq(req, false);
+ String securedWsClientResponse = sendWsReq(req, true);
+
+ out.println("<p>Person with ID 1 - unsecured request: <b>" + unsecuredWsClientResponse + "</b></p>");
+ out.println("<p>Person with ID 1 - secured request: <b>" + securedWsClientResponse + "</b></p>");
+ out.println("</body></html>");
+ out.flush();
+ out.close();
+ }
+
+ private String sendWsReq(HttpServletRequest req, boolean secured) {
+ JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
+ factory.setServiceClass(Person.class);
+ factory.setAddress("http://localhost:8282/PersonServiceCF");
+
+ Person simpleClient = (Person)factory.create();
+ java.lang.String _getPerson_personIdVal = "1";
+ javax.xml.ws.Holder<java.lang.String> _getPerson_personId = new javax.xml.ws.Holder<java.lang.String>(_getPerson_personIdVal);
+ javax.xml.ws.Holder<java.lang.String> _getPerson_ssn = new javax.xml.ws.Holder<java.lang.String>();
+ javax.xml.ws.Holder<java.lang.String> _getPerson_name = new javax.xml.ws.Holder<java.lang.String>();
+
+ // Attach Authorization header
+ if (secured) {
+ Client clientProxy = ClientProxy.getClient(simpleClient);
+
+ KeycloakSecurityContext session = (KeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+ Map<String, List<String>> headers = new HashMap<String, List<String>>();
+ headers.put("Authorization", Arrays.asList("Bearer " + session.getTokenString()));
+
+ clientProxy.getRequestContext().put(Message.PROTOCOL_HEADERS, headers);
+ }
+
+ try {
+ simpleClient.getPerson(_getPerson_personId, _getPerson_ssn, _getPerson_name);
+ return String.format("Person received: id=%s, name=%s, ssn=%s", _getPerson_personId.value, _getPerson_name.value, _getPerson_ssn.value);
+ } catch (UnknownPersonFault upf) {
+ return "UnknownPersonFault has occurred. Details: " + upf.toString();
+ } catch (WebServiceException wse) {
+ String error = "Can't receive person. Reason: " + wse.getMessage();
+ if (wse.getCause() != null) {
+ Throwable cause = wse.getCause();
+ error = error + " Details: " + cause.getClass().getName() + ": " + cause.getMessage();
+ }
+ return error;
+ }
+ }
+}
diff --git a/examples/fuse/product-app-fuse/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/examples/fuse/product-app-fuse/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 0000000..e6b0757
--- /dev/null
+++ b/examples/fuse/product-app-fuse/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+ <!-- USing jetty bean just for the compatibility with other fuse services -->
+ <bean id="servletConstraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">
+ <property name="constraint">
+ <bean class="org.eclipse.jetty.util.security.Constraint">
+ <property name="name" value="cst1"/>
+ <property name="roles">
+ <list>
+ <value>user</value>
+ </list>
+ </property>
+ <property name="authenticate" value="true"/>
+ <property name="dataConstraint" value="0"/>
+ </bean>
+ </property>
+ <property name="pathSpec" value="/product-portal/*"/>
+ </bean>
+
+ <bean id="keycloakPaxWebIntegration" class="org.keycloak.adapters.osgi.PaxWebIntegrationService"
+ init-method="start" destroy-method="stop">
+ <property name="jettyWebXmlLocation" value="/WEB-INF/jetty-web.xml" />
+ <property name="bundleContext" ref="blueprintBundleContext" />
+ <property name="constraintMappings">
+ <list>
+ <ref component-id="servletConstraintMapping" />
+ </list>
+ </property>
+ </bean>
+
+ <bean id="productServlet" class="org.keycloak.example.ProductPortalServlet" depends-on="keycloakPaxWebIntegration">
+ </bean>
+
+ <service ref="productServlet" interface="javax.servlet.Servlet">
+ <service-properties>
+ <entry key="alias" value="/product-portal" />
+ <entry key="servlet-name" value="ProductServlet" />
+ <entry key="keycloak.config.file" value="/keycloak.json" />
+ </service-properties>
+ </service>
+
+</blueprint>
\ No newline at end of file
diff --git a/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/jetty-web.xml b/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..e3d87a2
--- /dev/null
+++ b/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/jetty-web.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+ <Get name="securityHandler">
+ <Set name="authenticator">
+ <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+ </New>
+ </Set>
+ </Get>
+</Configure>
\ No newline at end of file
diff --git a/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/keycloak.json b/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/keycloak.json
new file mode 100644
index 0000000..2a52d24
--- /dev/null
+++ b/examples/fuse/product-app-fuse/src/main/resources/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+ "realm": "demo",
+ "resource": "product-portal",
+ "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "auth-server-url": "http://localhost:8080/auth",
+ "ssl-required" : "external",
+ "credentials": {
+ "secret": "password"
+ }
+}
examples/fuse/README.md 132(+132 -0)
diff --git a/examples/fuse/README.md b/examples/fuse/README.md
new file mode 100644
index 0000000..f918211
--- /dev/null
+++ b/examples/fuse/README.md
@@ -0,0 +1,132 @@
+Keycloak Fuse demo
+==================
+
+Currently Keycloak supports securing your web applications running inside [JBoss Fuse](http://www.jboss.org/products/fuse/overview/) or [Apache Karaf](http://karaf.apache.org/). It leverages Jetty8 adapter
+as both JBoss Fuse 6.1 and Apache Karaf 3 are bundled with [Jetty8](http://eclipse.org/jetty/) server under the covers and Jetty is used for running various kinds of web applications.
+
+The Fuse example is slightly modified version of Keycloak base demo applications. The main difference among base demo is that for Fuse demo
+are applications running on separate Fuse/Karaf server. Keycloak server is supposed to run separately on Wildfly 8 or JBoss EAP 6.3.
+
+What is supported for Fuse/Karaf is:
+* Security for classic WAR applications deployed on Fuse/Karaf with [pax-war extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War).
+* Security for servlets deployed on Fuse/Karaf as OSGI services with [pax-whiteboard extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard).
+* Security for [Apache Camel](http://camel.apache.org/) Jetty endpoints running with [camel-jetty](http://camel.apache.org/jetty.html) component.
+* Security for [Apache CXF](http://cxf.apache.org/) endpoints running on their own separate [Jetty engine](http://cxf.apache.org/docs/jetty-configuration.html).
+Supports both securing JAX-RS and JAX-WS endpoints.
+* Security for [Apache CXF](http://cxf.apache.org/) endpoints running on default engine provided by CXF servlet on [http://localhost:8181/cxf](http://localhost:8181/cxf)
+
+Fuse demo contains those basic applications:
+* **customer-app-fuse** A WAR application that is deployed with [pax-war extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War)
+* **product-app-fuse** A servlet application deployed with [pax-whiteboard extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard)
+* **cxf-jaxws** [Apache CXF](http://cxf.apache.org/) JAX-WS endpoint running on separate Jetty engine on [http://localhost:8282/PersonServiceCF](http://localhost:8282/PersonServiceCF).
+The product-app-fuse invokes the endpoint to get data.
+* **camel** [Apache Camel](http://camel.apache.org/) endpoint running on separate Jetty engine on [http://localhost:8383/admin-camel-endpoint](http://localhost:8383/admin-camel-endpoint).
+The customer-app-fuse invokes the endpoint to get data.
+* **cxf-jaxrs** [Apache CXF](http://cxf.apache.org/) JAX-RS endpoint running on default Jetty on [http://localhost:8181/cxf/customerservice](http://localhost:8181/cxf/customerservice).
+The customer-app-fuse invokes the endpoint to get data
+
+Running of demo consists of 2 steps. First you need to run separate Keycloak server and then Fuse/Karaf server with the applications
+
+Base steps
+----------
+
+* Run external instance of Keycloak server on WildFly 8 or JBoss EAP 6.3 . Fuse demo suppose that server is running on [http://localhost:8080/auth](http://localhost:8080/auth)
+* Import realm `demo` from the file testrealm.json on `examples/fuse/testrealm.json` .
+* Then build examples, which is needed so the feature repository is added to your local maven repo:
+
+```
+cd examples/fuse
+mvn clean install
+```
+
+Run demo applications on Apache Karaf 3.0.2
+-------------------------------------------
+
+Demo is using Apache camel and Apache CXF, which are not in standalone Karaf by default. So you will need to install feature repositories for both of them.
+Next step is to add feature repository for main set of Keycloak karaf features and for the demo. Once all feature URLs are added, you just need to install `keycloak-fuse-example` feature,
+which automatically installs all other needed stuff.
+
+Once you run Apache Karaf, you need to run these commands from Karaf console (Make sure to replace keycloak versions in the example with actual Keycloak version):
+
+```
+feature:repo-add mvn:org.apache.camel.karaf/apache-camel/2.12.5/xml/features
+feature:repo-add mvn:org.apache.cxf.karaf/apache-cxf/2.7.14/xml/features
+feature:repo-add mvn:org.keycloak/keycloak-osgi-features/1.1.0.Final/xml/features
+feature:repo-add mvn:org.keycloak.example.demo/keycloak-fuse-example-features/1.1.0.Final/xml/features
+feature:install keycloak-fuse-example
+```
+
+After that you can test running on [http://localhost:8080/customer-portal](http://localhost:8080/customer-portal) and login as "bburke@redhat.com" with password "password". Customer-portal is able to
+receive the response from the endpoints provided by `cxf-jaxrs` and `camel` applications. Note that camel endpoint is available just for users with role `admin`
+in this demo, so "bburke@redhat.com" can't access it. You may login as "admin" with password "password" in order to invoke camel endpoint.
+
+From [http://localhost:8080/product-portal](http://localhost:8080/product-portal) you will see servlet endpoint, which invokes JAX-WS provided by `cxf-jaxws` application.
+
+Note that this demo also secures whole default CXF endpoint on [http://localhost:8181/cxf](http://localhost:8181/cxf) hence every application running under it is secured too.
+
+Running example on JBoss Fuse 6.1.0.redhat-379
+----------------------------------------------
+
+Securing your applications on JBoss Fuse 6.1 is a bit more tricky. There is bug [https://ops4j1.jira.com/browse/PAXWEB-666](https://ops4j1.jira.com/browse/PAXWEB-666)
+, which doesn't easily allow to secure default Jetty engine on [http://localhost:8181](http://localhost:8181) as it's not possible to inject
+custom Jetty authenticator provided by Keycloak Jetty adapter into underlying Jetty server. Hence first step is to upgrade pax-web
+version from default 3.0.6 to newer 3.1.2 . Then you need to "refresh" cxf feature too. Final step is to install "keycloak-fuse-example" feature.
+
+All the steps could be performed with these commands in Fuse console (Replace Keycloak versions with the current version number again):
+
+```
+features:uninstall pax-war
+features:uninstall pax-http-whiteboard
+features:uninstall pax-http
+features:uninstall pax-jetty
+features:removeurl mvn:org.ops4j.pax.web/pax-web-features/3.0.6/xml/features
+features:addurl mvn:org.ops4j.pax.web/pax-web-features/3.1.2/xml/features
+
+features:addurl mvn:org.keycloak/keycloak-osgi-features/1.1.0.Final/xml/features
+features:addurl mvn:org.keycloak.example.demo/keycloak-fuse-example-features/1.1.0.Final/xml/features
+
+features:install keycloak-pax-web-upgrade
+features:install pax-http-whiteboard/3.1.2
+features:install pax-war/3.1.2
+
+features:uninstall cxf
+features:install cxf
+
+features:install keycloak-fuse-example
+```
+
+Now you can test example applications similarly like described for "Karaf" section.
+
+How to secure your own applications
+-----------------------------------
+Most of the steps should be understandable from testing and understanding the demo. Basically all mentioned applications require to
+ inject Keycloak Jetty authenticator into underlying Jetty server . The steps are bit different according to application type.
+
+**Classic WAR application** - Take a look at `customer-portal-app` for inspiration. The needed steps are:
+* Declare needed constraints in `/WEB-INF/web.xml`
+* Add `jetty-web.xml` file with the authenticator to `/WEB-INF/jetty-web.xml` and add `/WEB-INF/keycloak.json` with your Keycloak configuration
+* Make sure your WAR imports `org.keycloak.adapters.jetty` and maybe some more packages in MANIFEST.MF file in header `Import-Package`. It's
+recommended to use maven-bundle-plugin similarly like Fuse examples are doing, but note that "*" resolution for package doesn't import `org.keycloak.adapters.jetty` package
+as it's not used by application or Blueprint or Spring descriptor, but it's used just in jetty-web.xml file.
+
+**Servlet web application deployed by pax-whiteboard-extender** - Take a look at `product-portal-app` for inspiration. The needed steps are:
+* Keycloak provides PaxWebIntegrationService, which allows to inject jetty-authenticator.xml and configure security constraints for your application.
+Example `product-portal-app` declares this in `OSGI-INF/blueprint/blueprint.xml` . Note that your servlet needs to depend on it.
+* Steps 2,3 are same like for classic WAR
+
+**Apache camel application** - You can secure your Apache camel endpoint using [camel-jetty](http://camel.apache.org/jetty.html) endpoint by adding securityHandler with KeycloakJettyAuthenticator and
+proper security constraints injected. Take a look at `OSGI-INF/blueprint/blueprint.xml` configuration in `camel` application on example of how it can be done.
+
+**Apache CXF endpoint** - It's recommended to run your CXF endpoints secured by Keycloak on separate Jetty engine. Application `cxf-ws` is using separate endpoint on
+[http://localhost:8282](http://localhost:8282) . All the important configuration is declared in cxf-jaxws app in `META-INF/spring/beans.xml` .
+
+**Builtin web applications** - Some services automatically come with deployed servlets on startup. One of such examples is CXF servlet running on
+[http://localhost:8181/cxf](http://localhost:8181/cxf) context. Securing such endpoints is quite tricky. The approach, which Keycloak is currently using,
+is providing ServletUnregistrationService, which undeploys builtin servlet at startup, so you are able to re-deploy it again on context secured by Keycloak.
+You can see the `OSGI-INF/blueprint/blueprint.xml` inside `cxf-jaxrs` project, which adds JAX-RS "customerservice" endpoint and more importantly, it secures whole `/cxf` context.
+
+As a side effect, all other CXF services running on default CXF HTTP destination will be secured too. Once you uninstall feature "keycloak-fuse-example" the
+original unsecured servlet on `/cxf` context is deployed back and hence context will become unsecured again.
+
+It's recommended to use your own Jetty engine for your apps (similarly like `cxf-jaxws` application is doing).
+
\ No newline at end of file
examples/fuse/testrealm.json 135(+135 -0)
diff --git a/examples/fuse/testrealm.json b/examples/fuse/testrealm.json
new file mode 100644
index 0000000..d50066a
--- /dev/null
+++ b/examples/fuse/testrealm.json
@@ -0,0 +1,135 @@
+{
+ "realm": "demo",
+ "enabled": true,
+ "accessTokenLifespan": 60,
+ "accessCodeLifespan": 60,
+ "accessCodeLifespanUserAction": 300,
+ "ssoSessionIdleTimeout": 600,
+ "ssoSessionMaxLifespan": 36000,
+ "passwordCredentialGrantAllowed": true,
+ "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" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
+ },
+ {
+ "username" : "stian",
+ "enabled": true,
+ "email" : "stian@redhat.com",
+ "firstName": "Stian",
+ "lastName": "Thorgersen",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
+ },
+ {
+ "username" : "mposolda@redhat.com",
+ "enabled": true,
+ "email" : "mposolda@redhat.com",
+ "firstName": "Marek",
+ "lastName": "Posolda",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user" ],
+ "applicationRoles": {
+ "account": [ "manage-account" ]
+ }
+ },
+ {
+ "username" : "admin",
+ "enabled": true,
+ "email" : "admin@admin.com",
+ "firstName": "Admin",
+ "lastName": "Burke",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ],
+ "realmRoles": [ "user","admin" ],
+ "applicationRoles": {
+ "realm-management": [ "realm-admin" ]
+ }
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "User privileges"
+ },
+ {
+ "name": "admin",
+ "description": "Administrator privileges"
+ }
+ ]
+ },
+ "applications": [
+ {
+ "name": "customer-portal",
+ "enabled": true,
+ "adminUrl": "http://localhost:8181/customer-portal",
+ "baseUrl": "http://localhost:8181/customer-portal",
+ "redirectUris": [
+ "http://localhost:8181/customer-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "name": "product-portal",
+ "enabled": true,
+ "adminUrl": "http://localhost:8181/product-portal",
+ "baseUrl": "http://localhost:8181/product-portal",
+ "redirectUris": [
+ "http://localhost:8181/product-portal/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "name": "builtin-cxf-app",
+ "enabled": true,
+ "adminUrl": "http://localhost:8181/cxf",
+ "baseUrl": "http://localhost:8181/cxf",
+ "redirectUris": [
+ "http://localhost:8181/cxf/*"
+ ],
+ "secret": "password"
+ },
+ {
+ "name": "custom-cxf-endpoint",
+ "enabled": true,
+ "adminUrl": "http://localhost:8282/PersonServiceCF",
+ "baseUrl": "http://localhost:8282/PersonServiceCF",
+ "bearerOnly": true
+ },
+ {
+ "name": "admin-camel-endpoint",
+ "enabled": true,
+ "adminUrl": "http://localhost:8383/admin-camel-endpoint",
+ "baseUrl": "http://localhost:8383/admin-camel-endpoint",
+ "bearerOnly": true
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/js-console/src/main/webapp/index.html b/examples/js-console/src/main/webapp/index.html
index 4e3c803..796aebd 100644
--- a/examples/js-console/src/main/webapp/index.html
+++ b/examples/js-console/src/main/webapp/index.html
@@ -14,7 +14,6 @@
<button onclick="output(keycloak.refreshTokenParsed)">Show Refresh Token</button>
<button onclick="output(keycloak.idTokenParsed)">Show ID Token</button>
<button onclick="showExpires()">Show Expires</button>
- <button onclick="output(keycloak.idToken)">Show ID Token</button>
<button onclick="output(keycloak)">Show Details</button>
<button onclick="output(keycloak.createLoginUrl())">Show Login URL</button>
<button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
diff --git a/examples/multi-tenant/src/main/java/org/keycloak/example/multitenant/boundary/ProtectedServlet.java b/examples/multi-tenant/src/main/java/org/keycloak/example/multitenant/boundary/ProtectedServlet.java
index 991169d..ad41327 100644
--- a/examples/multi-tenant/src/main/java/org/keycloak/example/multitenant/boundary/ProtectedServlet.java
+++ b/examples/multi-tenant/src/main/java/org/keycloak/example/multitenant/boundary/ProtectedServlet.java
@@ -16,14 +16,15 @@
*/
package org.keycloak.example.multitenant.boundary;
-import java.io.IOException;
-import java.io.PrintWriter;
+import org.keycloak.KeycloakPrincipal;
+
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.keycloak.KeycloakPrincipal;
+import java.io.IOException;
+import java.io.PrintWriter;
/**
*
@@ -54,7 +55,7 @@ public class ProtectedServlet extends HttpServlet {
writer.write(principal.getKeycloakSecurityContext().getIdToken().getIssuer());
writer.write("<br/>User: ");
- writer.write(principal.getKeycloakSecurityContext().getIdToken().getPreferredUsername());
+ writer.write(principal.getKeycloakSecurityContext().getIdToken().getUserClaimSet().getPreferredUsername());
writer.write(String.format("<br/><a href=\"/multitenant/%s/logout\">Logout</a>", realm));
}
examples/pom.xml 1(+1 -0)
diff --git a/examples/pom.xml b/examples/pom.xml
index 3129a63..9a8a585 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -32,5 +32,6 @@
<module>js-console</module>
<module>multi-tenant</module>
<module>basic-auth</module>
+ <module>fuse</module>
</modules>
</project>
examples/README.md 10(+10 -0)
diff --git a/examples/README.md b/examples/README.md
index fd88529..f801ce6 100755
--- a/examples/README.md
+++ b/examples/README.md
@@ -58,3 +58,13 @@ Multi tenancy
-------------
A complete application, showing how to achieve multi tenancy of web applications by using one realm per account. For more information look at `multi-tenant/README.md`
+
+Basic authentication
+--------------------
+
+Example REST application configured to support both basic authentication with username/password as well as authentication with bearer token. For more information look at `basic-auth/README.md`
+
+Fuse
+----
+
+This is set of demo applications, showing how to secure your own web applications running inside OSGI environment in JBoss Fuse or Apache Karaf. Fore more information look at `fuse/README.md`
examples/saml/post-basic/README.md 2(+1 -1)
diff --git a/examples/saml/post-basic/README.md b/examples/saml/post-basic/README.md
index 951af23..1c3bde8 100755
--- a/examples/saml/post-basic/README.md
+++ b/examples/saml/post-basic/README.md
@@ -18,7 +18,7 @@ Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
a few steps you must follow.
Obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
diff --git a/examples/saml/post-with-encryption/README.md b/examples/saml/post-with-encryption/README.md
index 10be6c6..3867e4e 100755
--- a/examples/saml/post-with-encryption/README.md
+++ b/examples/saml/post-with-encryption/README.md
@@ -18,7 +18,7 @@ Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
a few steps you must follow.
Obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
diff --git a/examples/saml/post-with-signature/README.md b/examples/saml/post-with-signature/README.md
index 6bfd624..7e3e6d8 100755
--- a/examples/saml/post-with-signature/README.md
+++ b/examples/saml/post-with-signature/README.md
@@ -18,7 +18,7 @@ Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
a few steps you must follow.
Obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
diff --git a/examples/saml/redirect-basic/README.md b/examples/saml/redirect-basic/README.md
index dd764b6..ab44bee 100755
--- a/examples/saml/redirect-basic/README.md
+++ b/examples/saml/redirect-basic/README.md
@@ -18,7 +18,7 @@ Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
a few steps you must follow.
Obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
diff --git a/examples/saml/redirect-with-signature/README.md b/examples/saml/redirect-with-signature/README.md
index b185ff9..f0419bf 100755
--- a/examples/saml/redirect-with-signature/README.md
+++ b/examples/saml/redirect-with-signature/README.md
@@ -18,7 +18,7 @@ Make sure you've set up the Keycloak Server
The Keycloak Appliance Distribution comes with a preconfigured Keycloak server (based on Wildfly). You can use it out of
the box to run these demos. So, if you're using this, you can head to Step 2.
-Alternatively, you can install the Keycloak Server onto any JBoss AS 7.1.1, EAP 6.x, or Wildfly 8.x server, but there is
+Alternatively, you can install the Keycloak Server onto any EAP 6.x, or Wildfly 8.x server, but there is
a few steps you must follow.
Obtain latest keycloak-war-dist-all.zip. This distro is used to install Keycloak onto an existing JBoss installation.
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
index 3d80c2b..784f1b8 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/applications.js
@@ -332,10 +332,11 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
$scope.changed = false;
role = angular.copy($scope.role);
- var l = headers().location;
- var id = l.substring(l.lastIndexOf("/") + 1);
- $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles/" + id);
- Notifications.success("The role has been created.");
+ ApplicationRole.get({ realm: realm.realm, application : application.id, role: role.name }, function(role) {
+ var id = role.id;
+ $location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles/" + id);
+ Notifications.success("The role has been created.");
+ });
});
} else {
$scope.update();
@@ -347,7 +348,7 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
$scope.role.$remove({
realm : realm.realm,
application : application.id,
- role : $scope.role.name
+ role : $scope.role.id
}, function() {
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/roles");
Notifications.success("The role has been deleted.");
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 8e9573d..2f12f94 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -852,8 +852,6 @@ module.controller('RealmSessionStatsCtrl', function($scope, realm, stats, RealmA
$scope.realm = realm;
$scope.stats = stats;
- console.log(stats);
-
$scope.logoutAll = function() {
RealmLogoutAll.save({realm : realm.realm}, function (globalReqResult) {
var successCount = globalReqResult.successRequests ? globalReqResult.successRequests.length : 0;
@@ -863,16 +861,10 @@ module.controller('RealmSessionStatsCtrl', function($scope, realm, stats, RealmA
var msgStart = successCount>0 ? 'Successfully logout all users under: ' + globalReqResult.successRequests + ' . ' : '';
Notifications.error(msgStart + 'Failed to logout users under: ' + globalReqResult.failedRequests + '. Verify availability of failed hosts and try again');
} else {
- Notifications.success('Successfully logout all users from the realm');
+ window.location.reload();
}
-
- RealmApplicationSessionStats.query({realm: realm.realm}, function(updated) {
- $scope.stats = updated;
- })
});
};
-
-
});
@@ -960,10 +952,11 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, roles, applica
$scope.changed = false;
role = angular.copy($scope.role);
- var l = headers().location;
- var id = l.substring(l.lastIndexOf("/") + 1);
- $location.url("/realms/" + realm.realm + "/roles/" + id);
- Notifications.success("The role has been created.");
+ Role.get({ realm: realm.realm, role: role.name }, function(role) {
+ var id = role.id;
+ $location.url("/realms/" + realm.realm + "/roles/" + id);
+ Notifications.success("The role has been created.");
+ });
});
} else {
$scope.update();
@@ -974,7 +967,7 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, roles, applica
Dialog.confirmDelete($scope.role.name, 'role', function () {
$scope.role.$remove({
realm: realm.realm,
- role: $scope.role.name
+ role: $scope.role.id
}, function () {
$location.url("/realms/" + realm.realm + "/roles");
Notifications.success("The role has been deleted.");
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
index cb467f4..dda0e81 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/loaders.js
@@ -137,8 +137,8 @@ module.factory('UserFederatedIdentityLoader', function(Loader, UserFederatedIden
-module.factory('RoleLoader', function(Loader, Role, $route, $q) {
- return Loader.get(Role, function() {
+module.factory('RoleLoader', function(Loader, RoleById, $route, $q) {
+ return Loader.get(RoleById, function() {
return {
realm : $route.current.params.realm,
role : $route.current.params.role
@@ -154,8 +154,8 @@ module.factory('RoleListLoader', function(Loader, Role, $route, $q) {
});
});
-module.factory('ApplicationRoleLoader', function(Loader, ApplicationRole, $route, $q) {
- return Loader.get(ApplicationRole, function() {
+module.factory('ApplicationRoleLoader', function(Loader, RoleById, $route, $q) {
+ return Loader.get(RoleById, function() {
return {
realm : $route.current.params.realm,
application : $route.current.params.application,
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
index e0ff6a6..48d290d 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-detail.html
@@ -40,7 +40,7 @@
required> -->
</div>
</div>
- <div class="form-group clearfix block">
+ <div class="form-group clearfix block" data-ng-hide="create">
<label class="col-sm-2 control-label" for="compositeSwitch" class="control-label">Composite Roles</label>
<div class="col-sm-4">
<input ng-model="compositeSwitch" name="compositeSwitch" id="compositeSwitch" ng-disabled="compositeSwitchDisabled" onoffswitch />
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
index e21b12d..b9b7011 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-role-list.html
@@ -52,7 +52,7 @@
-->
<tbody>
<tr ng-repeat="role in roles">
- <td><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles/{{role.name}}">{{role.name}}</a></td>
+ <td><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles/{{role.id}}">{{role.name}}</a></td>
<td>{{role.composite}}</td>
<td>{{role.description}}</td>
</tr>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
index 2a7360d..10ee5a5 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/application-sessions.html
@@ -34,7 +34,7 @@
<th>Session Start</th>
</tr>
</thead>
- <tfoot data-ng-show="sessions && sessions.length > 5">
+ <tfoot data-ng-show="sessions && (sessions.length >= 5 || query.first != 0)">
<tr>
<td colspan="7">
<div class="table-nav">
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-detail.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-detail.html
index 23aaea8..06fa783 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-detail.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-detail.html
@@ -29,7 +29,7 @@
<textarea class="form-control" rows="5" cols="50" id="description" name="description" data-ng-model="role.description"></textarea>
</div>
</div>
- <div class="form-group">
+ <div class="form-group" data-ng-hide="create">
<label class="col-sm-2 control-label" for="compositeSwitch" class="control-label">Composite Roles</label>
<div class="col-sm-4">
<input ng-model="compositeSwitch" name="compositeSwitch" id="compositeSwitch" ng-disabled="compositeSwitchDisabled" onoffswitch />
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-list.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-list.html
index 21cc9ea..74a8670 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-list.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/role-list.html
@@ -46,7 +46,7 @@
-->
<tbody>
<tr ng-repeat="role in roles | filter:{name: searchQuery}">
- <td><a href="#/realms/{{realm.realm}}/roles/{{role.name}}">{{role.name}}</a></td>
+ <td><a href="#/realms/{{realm.realm}}/roles/{{role.id}}">{{role.name}}</a></td>
<td>{{role.composite}}</td>
<td>{{role.description}}</td>
</tr>
diff --git a/forms/common-themes/src/main/resources/theme/login/base/code.ftl b/forms/common-themes/src/main/resources/theme/login/base/code.ftl
index 23ca6a8..eb84d7b 100755
--- a/forms/common-themes/src/main/resources/theme/login/base/code.ftl
+++ b/forms/common-themes/src/main/resources/theme/login/base/code.ftl
@@ -10,7 +10,7 @@
<div id="kc-code">
<#if code.success>
<p>Please copy this code and paste it into your application:</p>
- <textarea id="code" class="${properties.kcTextareaClass!}">${code.code}</textarea>
+ <input id="code" class="${properties.kcTextareaClass!}" value="${code.code}"/>
<#else>
<p id="error">${code.error}</p>
</#if>
integration/adapter-core/pom.xml 44(+44 -0)
diff --git a/integration/adapter-core/pom.xml b/integration/adapter-core/pom.xml
index 567030d..80fa568 100755
--- a/integration/adapter-core/pom.xml
+++ b/integration/adapter-core/pom.xml
@@ -13,6 +13,17 @@
<name>Keycloak Adapter Core</name>
<description/>
+ <properties>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.keycloak.*;version="${project.version}",
+ org.apache.http.*;version=${keycloak.apache.httpcomponents.version},
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ </properties>
+
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
@@ -73,6 +84,39 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
index e0551fc..371696b 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
@@ -1,14 +1,15 @@
package org.keycloak.adapters;
-import java.util.Collections;
-import java.util.Set;
-
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.UserClaimSet;
import org.keycloak.util.UriUtils;
+import java.util.Collections;
+import java.util.Set;
+
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
@@ -16,15 +17,27 @@ public class AdapterUtils {
private static Logger log = Logger.getLogger(AdapterUtils.class);
- public static String getOrigin(String browserRequestURL, KeycloakSecurityContext session) {
+ /**
+ * Best effort to find origin for REST request calls from web UI application to REST application. In case of relative or absolute
+ * "auth-server-url" is returned the URL from request. In case of "auth-server-url-for-backend-request" used in configuration, it returns
+ * the origin of auth server.
+ *
+ * This may be the optimization in cluster, so if you have keycloak and applications on same host, the REST request doesn't need to
+ * go through loadbalancer, but can be sent directly to same host.
+ *
+ * @param browserRequestURL
+ * @param session
+ * @return
+ */
+ public static String getOriginForRestCalls(String browserRequestURL, KeycloakSecurityContext session) {
if (session instanceof RefreshableKeycloakSecurityContext) {
KeycloakDeployment deployment = ((RefreshableKeycloakSecurityContext)session).getDeployment();
switch (deployment.getRelativeUrls()) {
case ALL_REQUESTS:
+ case NEVER:
// Resolve baseURI from the request
return UriUtils.getOrigin(browserRequestURL);
case BROWSER_ONLY:
- case NEVER:
// Resolve baseURI from the codeURL (This is already non-relative and based on our hostname)
return UriUtils.getOrigin(deployment.getCodeUrl());
default:
@@ -65,20 +78,22 @@ public class AdapterUtils {
String attr = "sub";
if (deployment.getPrincipalAttribute() != null) attr = deployment.getPrincipalAttribute();
String name = null;
+ UserClaimSet claimSet = token.getUserClaimSet();
+
if ("sub".equals(attr)) {
name = token.getSubject();
} else if ("email".equals(attr)) {
- name = token.getEmail();
+ name = claimSet.getEmail();
} else if ("preferred_username".equals(attr)) {
- name = token.getPreferredUsername();
+ name = claimSet.getPreferredUsername();
} else if ("name".equals(attr)) {
- name = token.getName();
+ name = claimSet.getName();
} else if ("given_name".equals(attr)) {
- name = token.getGivenName();
+ name = claimSet.getGivenName();
} else if ("family_name".equals(attr)) {
- name = token.getFamilyName();
+ name = claimSet.getFamilyName();
} else if ("nickname".equals(attr)) {
- name = token.getNickName();
+ name = claimSet.getNickName();
}
if (name == null) name = token.getSubject();
return name;
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/BearerTokenLoginModule.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/BearerTokenLoginModule.java
index 09b4816..10f8d7b 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/BearerTokenLoginModule.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/jaas/BearerTokenLoginModule.java
@@ -6,7 +6,7 @@ import org.keycloak.VerificationException;
/**
* Login module, which allows to authenticate Keycloak access token in environments, which rely on JAAS
* <p/>
- * It expects login based on username and password where username must be equal to "Bearer" and password is keycloak access token.
+ * It expects login based on username and password where username doesn't matter and password is keycloak access token.
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
integration/installed/pom.xml 4(+4 -0)
diff --git a/integration/installed/pom.xml b/integration/installed/pom.xml
index 186c9d9..29df75d 100755
--- a/integration/installed/pom.xml
+++ b/integration/installed/pom.xml
@@ -45,6 +45,10 @@
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ </dependency>
</dependencies>
<build>
diff --git a/integration/jaxrs-oauth-client/pom.xml b/integration/jaxrs-oauth-client/pom.xml
index 441f2cc..86d43fc 100755
--- a/integration/jaxrs-oauth-client/pom.xml
+++ b/integration/jaxrs-oauth-client/pom.xml
@@ -74,7 +74,6 @@
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>4.3.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
integration/jetty/jetty8.1/pom.xml 41(+41 -0)
diff --git a/integration/jetty/jetty8.1/pom.xml b/integration/jetty/jetty8.1/pom.xml
index 3c1f6ea..8ea3c55 100755
--- a/integration/jetty/jetty8.1/pom.xml
+++ b/integration/jetty/jetty8.1/pom.xml
@@ -13,6 +13,14 @@
<name>Keycloak Jetty 8.1.x Integration</name>
<properties>
<jetty9.version>8.1.16.v20140903</jetty9.version>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.jetty.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ javax.servlet.*;version="[2.5,4)";resolution:=optional,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
</properties>
<description />
@@ -99,6 +107,39 @@
<target>1.6</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java b/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
index e2dcfa5..38180aa 100755
--- a/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
+++ b/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
@@ -4,6 +4,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
diff --git a/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index d1ae6e0..a3a5572 100755
--- a/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/integration/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest;
integration/jetty/jetty9.1/pom.xml 42(+42 -0)
diff --git a/integration/jetty/jetty9.1/pom.xml b/integration/jetty/jetty9.1/pom.xml
index 689a0e3..5601a87 100755
--- a/integration/jetty/jetty9.1/pom.xml
+++ b/integration/jetty/jetty9.1/pom.xml
@@ -13,6 +13,15 @@
<name>Keycloak Jetty 9.1.x Integration</name>
<properties>
<jetty9.version>9.1.5.v20140505</jetty9.version>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.jetty.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.eclipse.jetty.*;version="[9.1,9.2)";resolution:=optional,
+ javax.servlet.*;version="[3.0,4)";resolution:=optional,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
</properties>
<description />
@@ -113,6 +122,39 @@
<target>1.6</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java b/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
index 24fc9b2..6d4cb92 100755
--- a/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
+++ b/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
@@ -5,6 +5,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
diff --git a/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index db15f33..d1ab5f3 100755
--- a/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/integration/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest;
integration/jetty/jetty9.2/pom.xml 42(+42 -0)
diff --git a/integration/jetty/jetty9.2/pom.xml b/integration/jetty/jetty9.2/pom.xml
index 0e15ff0..22c0bab 100755
--- a/integration/jetty/jetty9.2/pom.xml
+++ b/integration/jetty/jetty9.2/pom.xml
@@ -13,6 +13,15 @@
<name>Keycloak Jetty 9.2.x Integration</name>
<properties>
<jetty9.version>9.2.4.v20141103</jetty9.version>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.jetty.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.eclipse.jetty.*;resolution:=optional,
+ javax.servlet.*;version="[3.0,4)";resolution:=optional,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
</properties>
<description />
@@ -99,6 +108,39 @@
<target>1.6</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java b/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
index 4ff9af9..f48a0d8 100755
--- a/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
+++ b/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/JettySessionTokenStore.java
@@ -5,10 +5,10 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession;
-import java.lang.reflect.Field;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
diff --git a/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index b43e27c..6cd1e07 100755
--- a/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/integration/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest;
integration/jetty/jetty-core/pom.xml 42(+42 -0)
diff --git a/integration/jetty/jetty-core/pom.xml b/integration/jetty/jetty-core/pom.xml
index 4415a69..b424977 100755
--- a/integration/jetty/jetty-core/pom.xml
+++ b/integration/jetty/jetty-core/pom.xml
@@ -13,6 +13,15 @@
<name>Keycloak Jetty Core Integration</name>
<properties>
<jetty9.version>8.1.16.v20140903</jetty9.version>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.jetty.core.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.eclipse.jetty.*;version="[8.1,10)";resolution:=optional,
+ javax.servlet.*;version="[2.5,4)";resolution:=optional,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
</properties>
<description />
@@ -94,6 +103,39 @@
<target>1.6</target>
</configuration>
</plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
</plugins>
</build>
diff --git a/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/WrappingSessionHandler.java b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/WrappingSessionHandler.java
new file mode 100644
index 0000000..529b6f0
--- /dev/null
+++ b/integration/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/WrappingSessionHandler.java
@@ -0,0 +1,30 @@
+package org.keycloak.adapters.jetty.core;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.server.session.SessionHandler;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class WrappingSessionHandler extends SessionHandler {
+
+ public WrappingSessionHandler() {
+ super();
+ }
+
+ public WrappingSessionHandler(SessionManager mgr) {
+ super(mgr);
+ }
+
+ @Override
+ public void setHandler(Handler handler) {
+ if (getHandler() != null && getHandler() instanceof HandlerWrapper) {
+ HandlerWrapper wrappedHandler = (HandlerWrapper) getHandler();
+ wrappedHandler.setHandler(handler);
+ } else {
+ super.setHandler(handler);
+ }
+ }
+}
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index 51e564d..5161cb1 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -120,7 +120,7 @@
redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'prompt=' + options.prompt;
}
- sessionStorage.oauthState = state;
+ sessionStorage.oauthState = JSON.stringify({ state: state, redirectUri: encodeURIComponent(redirectUri) });
var url = getRealmUrl()
+ '/tokens/login'
@@ -204,6 +204,31 @@
return promise.promise;
}
+ kc.loadUserInfo = function() {
+ var url = getRealmUrl() + '/protocol/openid-connect/userinfo';
+ var req = new XMLHttpRequest();
+ req.open('GET', url, true);
+ req.setRequestHeader('Accept', 'application/json');
+ req.setRequestHeader('Authorization', 'bearer ' + kc.token);
+
+ var promise = createPromise();
+
+ req.onreadystatechange = function () {
+ if (req.readyState == 4) {
+ if (req.status == 200) {
+ kc.userInfo = JSON.parse(req.responseText);
+ promise.setSuccess(kc.userInfo);
+ } else {
+ promise.setError();
+ }
+ }
+ }
+
+ req.send();
+
+ return promise.promise;
+ }
+
kc.isTokenExpired = function(minValidity) {
if (!kc.tokenParsed || !kc.refreshToken) {
throw 'Not authenticated';
@@ -315,6 +340,8 @@
params += '&client_id=' + encodeURIComponent(kc.clientId);
}
+ params += '&redirect_uri=' + oauth.redirectUri;
+
req.withCredentials = true;
req.onreadystatechange = function() {
@@ -538,9 +565,13 @@
}
}
- if ((oauth.code || oauth.error) && oauth.state && oauth.state == sessionStorage.oauthState) {
+ var sessionState = sessionStorage.oauthState && JSON.parse(sessionStorage.oauthState);
+
+ if (sessionState && (oauth.code || oauth.error) && oauth.state && oauth.state == sessionState.state) {
delete sessionStorage.oauthState;
+ oauth.redirectUri = sessionState.redirectUri;
+
if (oauth.fragment) {
oauth.newUrl += '#' + oauth.fragment;
}
integration/osgi-adapter/pom.xml 104(+104 -0)
diff --git a/integration/osgi-adapter/pom.xml b/integration/osgi-adapter/pom.xml
new file mode 100644
index 0000000..dcacca4
--- /dev/null
+++ b/integration/osgi-adapter/pom.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-osgi-adapter</artifactId>
+ <name>Keycloak OSGI Adapter</name>
+ <packaging>jar</packaging>
+
+ <properties>
+ <jetty9.version>8.1.16.v20140903</jetty9.version>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.osgi.*
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ org.ops4j.pax.web.*;version="[3.0,4)",
+ javax.servlet.*;version="[2.5,4)";resolution:=optional,
+ org.eclipse.jetty.*;version="[8.1,10)";resolution:=optional,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.enterprise</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-runtime</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-ClassPath>.</Bundle-ClassPath>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java b/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java
new file mode 100644
index 0000000..1aa67f0
--- /dev/null
+++ b/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java
@@ -0,0 +1,163 @@
+package org.keycloak.adapters.osgi;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.util.security.Constraint;
+import org.jboss.logging.Logger;
+import org.ops4j.pax.web.service.WebContainer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
+ * and allows to inject custom security constraint for securing resources by Keycloak.
+ *
+ * <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
+ * is true in karaf/fuse environment</p>
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PaxWebIntegrationService {
+
+ protected static final Logger log = Logger.getLogger(PaxWebIntegrationService.class);
+
+ private BundleContext bundleContext;
+ private String jettyWebXmlLocation;
+ private List<ConstraintMapping> constraintMappings; // Using jetty constraint mapping just because of compatibility with other fuse services
+
+ private ServiceTracker webContainerTracker;
+ private HttpContext httpContext;
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public String getJettyWebXmlLocation() {
+ return jettyWebXmlLocation;
+ }
+
+ public void setJettyWebXmlLocation(String jettyWebXmlLocation) {
+ this.jettyWebXmlLocation = jettyWebXmlLocation;
+ }
+
+ public List<ConstraintMapping> getConstraintMappings() {
+ return constraintMappings;
+ }
+
+ public void setConstraintMappings(List<ConstraintMapping> constraintMappings) {
+ this.constraintMappings = constraintMappings;
+ }
+
+ protected ServiceTracker getWebContainerTracker() {
+ return webContainerTracker;
+ }
+
+ protected HttpContext getHttpContext() {
+ return httpContext;
+ }
+
+
+ public void start() {
+ ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
+
+ @Override
+ public Object addingService(ServiceReference reference) {
+ return addingWebContainerCallback(reference);
+ }
+
+ @Override
+ public void modifiedService(ServiceReference reference, Object service) {
+ }
+
+ @Override
+ public void removedService(ServiceReference reference, Object service) {
+ removingWebContainerCallback(reference);
+ }
+ };
+
+ webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
+ webContainerTracker.open();
+ }
+
+ public void stop() {
+ webContainerTracker.remove(webContainerTracker.getServiceReference());
+ }
+
+ protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
+ WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
+ httpContext = service.createDefaultHttpContext();
+
+ addJettyWebXml(service);
+
+ if (constraintMappings == null) {
+ throw new IllegalStateException("constraintMappings was null!");
+ }
+ for (ConstraintMapping constraintMapping : constraintMappings) {
+ addConstraintMapping(service, constraintMapping);
+ }
+
+ service.registerLoginConfig("BASIC", "does-not-matter", null, null, httpContext);
+
+ return service;
+ }
+
+ protected void addJettyWebXml(WebContainer service) {
+ String jettyWebXmlLoc;
+ if (this.jettyWebXmlLocation == null) {
+ jettyWebXmlLoc = "/WEB-INF/jetty-web.xml";
+ } else {
+ jettyWebXmlLoc = this.jettyWebXmlLocation;
+ }
+
+ URL jettyWebXml = bundleContext.getBundle().getResource(jettyWebXmlLoc);
+ if (jettyWebXml != null) {
+ log.debug("Found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
+ service.registerJettyWebXml(jettyWebXml, httpContext);
+ } else {
+ log.debug("Not found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
+ }
+ }
+
+ protected void addConstraintMapping(WebContainer service, ConstraintMapping constraintMapping) {
+ Constraint constraint = constraintMapping.getConstraint();
+ String[] roles = constraint.getRoles();
+ // name property is unavailable on constraint object :/
+ String name = "Constraint-" + new Random().nextInt();
+
+ int dataConstraint = constraint.getDataConstraint();
+ String dataConstraintStr;
+ switch (dataConstraint) {
+ case Constraint.DC_UNSET: dataConstraintStr = null; break;
+ case Constraint.DC_NONE: dataConstraintStr = "NONE"; break;
+ case Constraint.DC_CONFIDENTIAL: dataConstraintStr = "CONFIDENTIAL"; break;
+ case Constraint.DC_INTEGRAL: dataConstraintStr = "INTEGRAL"; break;
+ default:
+ log.warnv("Unknown data constraint: " + dataConstraint);
+ dataConstraintStr = "CONFIDENTIAL";
+ }
+ List<String> rolesList = Arrays.asList(roles);
+
+ log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ + constraint.getAuthenticate() + ", roles=" + rolesList);
+ service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
+ }
+
+ protected void removingWebContainerCallback(ServiceReference serviceReference) {
+ WebContainer service = (WebContainer)bundleContext.getService(serviceReference);
+ if (service != null) {
+ service.unregisterLoginConfig(httpContext);
+ service.unregisterConstraintMapping(httpContext);
+ }
+ }
+}
diff --git a/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/ServletUnregistrationService.java b/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/ServletUnregistrationService.java
new file mode 100644
index 0000000..236c49e
--- /dev/null
+++ b/integration/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/ServletUnregistrationService.java
@@ -0,0 +1,100 @@
+package org.keycloak.adapters.osgi;
+
+import java.util.Hashtable;
+
+import javax.servlet.Servlet;
+
+import org.jboss.logging.Logger;
+import org.ops4j.pax.web.service.WebContainer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+
+/**
+ * Service, which allows to remove previously registered servlets in karaf/fuse environment. It assumes that particular servlet was previously
+ * registered as service in OSGI container under {@link javax.servlet.Servlet} interface.
+ *
+ * <p>The point is to register automatically registered builtin servlet endpoints (like "/cxf" for instance) to allow secure them
+ * by Keycloak and re-register them again</p>
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ServletUnregistrationService {
+
+ protected static final Logger log = Logger.getLogger(ServletUnregistrationService.class);
+
+ private BundleContext bundleContext;
+ private ServiceReference servletReference;
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public ServiceReference getServletReference() {
+ return servletReference;
+ }
+
+ public void setServletReference(ServiceReference servletReference) {
+ this.servletReference = servletReference;
+ }
+
+ // TODO: Re-register original servlet back during stop?
+ public void start() {
+ if (servletReference == null) {
+ throw new IllegalStateException("No servlet reference provided");
+ }
+
+ Servlet servlet = (Servlet) bundleContext.getService(servletReference);
+ WebContainer webContainer = findWebContainer(servletReference);
+ if (webContainer == null) {
+ return;
+ }
+
+ // Unregister servlet now
+ try {
+ webContainer.unregisterServlet(servlet);
+ log.debugv("Original servlet with alias " + servletReference.getProperty("alias") + " unregistered successfully.");
+ } catch (IllegalStateException e) {
+ log.warnv("Can't unregister servlet due to: " + e.getMessage());
+ }
+ }
+
+ public void stop() {
+ try {
+ Servlet servlet = (Servlet) bundleContext.getService(servletReference);
+ WebContainer webContainer = findWebContainer(servletReference);
+ if (webContainer == null) {
+ return;
+ }
+
+ Hashtable<String, Object> servletInitParams = new Hashtable<String, Object>();
+ String[] propNames = servletReference.getPropertyKeys();
+ for (String propName : propNames) {
+ servletInitParams.put(propName, servletReference.getProperty(propName));
+ }
+
+ // Try to register original servlet back
+ HttpContext httpContext = webContainer.createDefaultHttpContext();
+ String alias = (String) servletReference.getProperty("alias");
+ webContainer.registerServlet(alias, servlet, servletInitParams, httpContext);
+ } catch (Exception e) {
+ log.warn("Can't register original servlet back", e);
+ }
+ }
+
+ protected WebContainer findWebContainer(ServiceReference servletRef) {
+ BundleContext servletBundleContext = servletRef.getBundle().getBundleContext();
+ ServiceReference webContainerReference = servletBundleContext.getServiceReference(WebContainer.class.getName());
+ if (webContainerReference == null) {
+ log.warn("Not found webContainer reference for bundle " + servletBundleContext);
+ return null;
+ } else {
+ return (WebContainer) servletBundleContext.getService(webContainerReference);
+ }
+ }
+
+}
integration/pom.xml 1(+1 -0)
diff --git a/integration/pom.xml b/integration/pom.xml
index e114ad5..c14ec59 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -28,5 +28,6 @@
<module>js</module>
<module>installed</module>
<module>admin-client</module>
+ <module>osgi-adapter</module>
</modules>
</project>
pom.xml 20(+19 -1)
diff --git a/pom.xml b/pom.xml
index afc7119..243338e 100755
--- a/pom.xml
+++ b/pom.xml
@@ -13,6 +13,7 @@
<properties>
<aesh.version>0.33.12</aesh.version>
+ <base64.version>2.3.8</base64.version>
<bouncycastle.version>1.46</bouncycastle.version>
<jackson.version>1.9.9</jackson.version>
<keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
@@ -48,6 +49,8 @@
<infinispan.version>6.0.2.Final</infinispan.version>
<liquibase.version>3.2.2</liquibase.version>
<jetty9.version>9.1.0.v20131115</jetty9.version>
+ <osgi.version>4.2.0</osgi.version>
+ <pax.web.version>3.1.2</pax.web.version>
<!-- maven-compiler-plugin -->
<maven.compiler.target>1.6</maven.compiler.target>
@@ -139,7 +142,7 @@
<dependency>
<groupId>net.iharder</groupId>
<artifactId>base64</artifactId>
- <version>2.3.8</version>
+ <version>${base64.version}</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
@@ -508,6 +511,21 @@
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.enterprise</artifactId>
+ <version>${osgi.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-runtime</artifactId>
+ <version>${pax.web.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 8c92fe9..6a8cb7f 100755
--- a/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -4,6 +4,7 @@
<module name="org.apache.httpcomponents"/>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.jboss.xnio"/>
</dependencies>
<exclusions>
</exclusions>
diff --git a/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/keycloak.json b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..70c79a1
--- /dev/null
+++ b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,8 @@
+{
+ "realm" : "aerogear",
+ "auth-server-url" : "/auth",
+ "ssl-required" : "external",
+ "resource" : "unified-push-server",
+ "public-client" : true,
+ "disable-trust-manager" : true
+}
\ No newline at end of file
diff --git a/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/web.xml b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/web.xml
index 77b633e..d569afe 100755
--- a/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/web.xml
+++ b/project-integrations/aerogear-ups/app/src/main/webapp/WEB-INF/web.xml
@@ -6,11 +6,6 @@
<module-name>aerogear-ups</module-name>
- <listener>
- <listener-class>org.keycloak.example.BootstrapListener</listener-class>
- </listener>
-
-
<security-constraint>
<web-resource-collection>
<web-resource-name>UPS</web-resource-name>
@@ -19,11 +14,6 @@
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
- <!--
- <user-data-constraint>
- <transport-guarantee>CONFIDENTIAL</transport-guarantee>
- </user-data-constraint>
- -->
</security-constraint>
<security-constraint>
@@ -34,11 +24,6 @@
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
- <!--
- <user-data-constraint>
- <transport-guarantee>CONFIDENTIAL</transport-guarantee>
- </user-data-constraint>
- -->
</security-constraint>
<login-config>
@@ -53,7 +38,4 @@
<role-name>user</role-name>
</security-role>
-
-
-
</web-app>
diff --git a/project-integrations/aerogear-ups/auth-server/pom.xml b/project-integrations/aerogear-ups/auth-server/pom.xml
index b3abb2f..35cdedd 100755
--- a/project-integrations/aerogear-ups/auth-server/pom.xml
+++ b/project-integrations/aerogear-ups/auth-server/pom.xml
@@ -33,7 +33,6 @@
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
-
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-connections-jpa</artifactId>
@@ -41,6 +40,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-connections-jpa-liquibase</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 0925383..f995611 100755
--- a/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/project-integrations/aerogear-ups/auth-server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -2,10 +2,10 @@
<deployment>
<dependencies>
<module name="org.apache.httpcomponents"/>
- <module name="org.bouncycastle"/>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
<module name="org.codehaus.jackson.jackson-core-asl"/>
<module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.infinispan"/>
</dependencies>
<exclusions>
<module name="org.jboss.resteasy.resteasy-jackson2-provider"/>
@@ -16,5 +16,8 @@
<module name="org.keycloak.keycloak-undertow-adapter" />
<module name="org.keycloak.keycloak-as7-adapter" />
</exclusions>
+ <exclude-subsystems>
+ <subsystem name="webservices"/>
+ </exclude-subsystems>
</deployment>
</jboss-deployment-structure>
\ No newline at end of file
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintAuthorizationHandler.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintAuthorizationHandler.java
index 9889d51..c497565 100755
--- a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintAuthorizationHandler.java
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ConstraintAuthorizationHandler.java
@@ -4,10 +4,9 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString;
import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
+import org.keycloak.representations.UserClaimSet;
import org.keycloak.representations.IDToken;
-import java.util.Collection;
-
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@@ -65,14 +64,17 @@ public class ConstraintAuthorizationHandler implements HttpHandler {
if (idToken.getSubject() != null) {
exchange.getRequestHeaders().put(KEYCLOAK_SUBJECT, idToken.getSubject());
}
- if (idToken.getPreferredUsername() != null) {
- exchange.getRequestHeaders().put(KEYCLOAK_USERNAME, idToken.getPreferredUsername());
+
+ UserClaimSet claimSet = idToken.getUserClaimSet();
+
+ if (claimSet.getPreferredUsername() != null) {
+ exchange.getRequestHeaders().put(KEYCLOAK_USERNAME, claimSet.getPreferredUsername());
}
- if (idToken.getEmail() != null) {
- exchange.getRequestHeaders().put(KEYCLOAK_EMAIL, idToken.getEmail());
+ if (claimSet.getEmail() != null) {
+ exchange.getRequestHeaders().put(KEYCLOAK_EMAIL, claimSet.getEmail());
}
- if (idToken.getName() != null) {
- exchange.getRequestHeaders().put(KEYCLOAK_NAME, idToken.getName());
+ if (claimSet.getName() != null) {
+ exchange.getRequestHeaders().put(KEYCLOAK_NAME, claimSet.getName());
}
if (sendAccessToken) {
exchange.getRequestHeaders().put(KEYCLOAK_ACCESS_TOKEN, account.getKeycloakSecurityContext().getTokenString());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
index 0781c04..9b9f8b9 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
@@ -8,6 +8,7 @@ import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.NotAcceptableException;
import org.jboss.resteasy.spi.NotFoundException;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.UnauthorizedException;
import org.keycloak.ClientConnection;
import org.keycloak.Config;
@@ -583,6 +584,7 @@ public class OpenIDConnectService {
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
.build();
}
+
ClientSessionModel clientSession = accessCode.getClientSession();
event.detail(Details.CODE_ID, clientSession.getId());
if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN)) {
@@ -601,6 +603,16 @@ public class OpenIDConnectService {
ClientModel client = authorizeClient(authorizationHeader, formData, event);
+ String redirectUri = clientSession.getNote(OpenIDConnect.REDIRECT_URI_PARAM);
+ if (redirectUri != null && !redirectUri.equals(formData.getFirst(OAuth2Constants.REDIRECT_URI))) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put(OAuth2Constants.ERROR, "invalid_grant");
+ res.put(OAuth2Constants.ERROR_DESCRIPTION, "Incorrect redirect_uri");
+ event.error(Errors.INVALID_CODE);
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
+ .build();
+ }
+
if (!client.getClientId().equals(clientSession.getClient().getClientId())) {
Map<String, String> res = new HashMap<String, String>();
res.put(OAuth2Constants.ERROR, "invalid_grant");
@@ -672,6 +684,15 @@ public class OpenIDConnectService {
return Cors.add(request, Response.ok(res)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
}
+ @Path("userinfo")
+ public Object issueUserInfo() {
+ UserInfoService userInfoEndpoint = new UserInfoService(this);
+
+ ResteasyProviderFactory.getInstance().injectProperties(userInfoEndpoint);
+
+ return userInfoEndpoint;
+ }
+
protected ClientModel authorizeClient(String authorizationHeader, MultivaluedMap<String, String> formData, EventBuilder event) {
ClientModel client = authorizeClientBase(authorizationHeader, formData, event, realm);
@@ -784,6 +805,7 @@ public class OpenIDConnectService {
event.error(Errors.NOT_ALLOWED);
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "direct-grants-only clients are not allowed to initiate browser login");
}
+ String redirectUriParam = redirect;
redirect = verifyRedirectUri(uriInfo, redirect, realm, client);
if (redirect == null) {
event.error(Errors.INVALID_REDIRECT_URI);
@@ -795,6 +817,7 @@ public class OpenIDConnectService {
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
clientSession.setNote(OpenIDConnect.STATE_PARAM, state);
+ clientSession.setNote(OpenIDConnect.REDIRECT_URI_PARAM, redirectUriParam);
if (scopeParam != null) clientSession.setNote(OpenIDConnect.SCOPE_PARAM, scopeParam);
if (responseType != null) clientSession.setNote(OpenIDConnect.RESPONSE_TYPE_PARAM, responseType);
if (loginHint != null) clientSession.setNote(OpenIDConnect.LOGIN_HINT_PARAM, loginHint);
@@ -1137,4 +1160,11 @@ public class OpenIDConnectService {
return Response.status(status).entity(e).type("application/json").build();
}
+ TokenManager getTokenManager() {
+ return this.tokenManager;
+ }
+
+ RealmModel getRealm() {
+ return this.realm;
+ }
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index 219f1a1..a72aa1c 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -20,6 +20,7 @@ import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.UserClaimSet;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.services.managers.AuthenticationManager;
@@ -185,7 +186,7 @@ public class TokenManager {
for (Map.Entry<String, AccessToken.Access> entry : token.getResourceAccess().entrySet()) {
ApplicationModel app = realm.getApplicationByName(entry.getKey());
if (app == null) {
- throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Application no longer exists", "Application no longer exists: " + app.getName());
+ throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Application no longer exists", "Application no longer exists: " + entry.getKey());
}
for (String roleName : entry.getValue().getRoles()) {
RoleModel role = app.getRole(roleName);
@@ -199,26 +200,27 @@ public class TokenManager {
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has application scope" + roleName);
}
}
-
}
}
}
- public void initClaims(IDToken token, ClientModel model, UserModel user) {
+ public void initClaims(UserClaimSet claimSet, ClientModel model, UserModel user) {
+ claimSet.setSubject(user.getId());
+
if (ClaimMask.hasUsername(model.getAllowedClaimsMask())) {
- token.setPreferredUsername(user.getUsername());
+ claimSet.setPreferredUsername(user.getUsername());
}
if (ClaimMask.hasEmail(model.getAllowedClaimsMask())) {
- token.setEmail(user.getEmail());
- token.setEmailVerified(user.isEmailVerified());
+ claimSet.setEmail(user.getEmail());
+ claimSet.setEmailVerified(user.isEmailVerified());
}
if (ClaimMask.hasName(model.getAllowedClaimsMask())) {
- token.setFamilyName(user.getLastName());
- token.setGivenName(user.getFirstName());
+ claimSet.setFamilyName(user.getLastName());
+ claimSet.setGivenName(user.getFirstName());
StringBuilder fullName = new StringBuilder();
if (user.getFirstName() != null) fullName.append(user.getFirstName()).append(" ");
if (user.getLastName() != null) fullName.append(user.getLastName());
- token.setName(fullName.toString());
+ claimSet.setName(fullName.toString());
}
}
@@ -233,7 +235,8 @@ public class TokenManager {
if (realm.getAccessTokenLifespan() > 0) {
token.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
}
- initClaims(token, claimer, user);
+ UserClaimSet claimSet = token.getUserClaimSet();
+ initClaims(claimSet, claimer, user);
return token;
}
@@ -257,7 +260,8 @@ public class TokenManager {
if (allowedOrigins != null) {
token.setAllowedOrigins(allowedOrigins);
}
- initClaims(token, client, user);
+ UserClaimSet claimSet = token.getUserClaimSet();
+ initClaims(claimSet, client, user);
return token;
}
@@ -354,30 +358,30 @@ public class TokenManager {
if (realm.getAccessTokenLifespan() > 0) {
idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
}
- idToken.setPreferredUsername(accessToken.getPreferredUsername());
- idToken.setGivenName(accessToken.getGivenName());
- idToken.setMiddleName(accessToken.getMiddleName());
- idToken.setFamilyName(accessToken.getFamilyName());
- idToken.setName(accessToken.getName());
- idToken.setNickName(accessToken.getNickName());
- idToken.setGender(accessToken.getGender());
- idToken.setPicture(accessToken.getPicture());
- idToken.setProfile(accessToken.getProfile());
- idToken.setWebsite(accessToken.getWebsite());
- idToken.setBirthdate(accessToken.getBirthdate());
- idToken.setEmail(accessToken.getEmail());
- idToken.setEmailVerified(accessToken.getEmailVerified());
- idToken.setLocale(accessToken.getLocale());
- idToken.setFormattedAddress(accessToken.getFormattedAddress());
- idToken.setAddress(accessToken.getAddress());
- idToken.setStreetAddress(accessToken.getStreetAddress());
- idToken.setLocality(accessToken.getLocality());
- idToken.setRegion(accessToken.getRegion());
- idToken.setPostalCode(accessToken.getPostalCode());
- idToken.setCountry(accessToken.getCountry());
- idToken.setPhoneNumber(accessToken.getPhoneNumber());
- idToken.setPhoneNumberVerified(accessToken.getPhoneNumberVerified());
- idToken.setZoneinfo(accessToken.getZoneinfo());
+ idToken.getUserClaimSet().setPreferredUsername(accessToken.getUserClaimSet().getPreferredUsername());
+ idToken.getUserClaimSet().setGivenName(accessToken.getUserClaimSet().getGivenName());
+ idToken.getUserClaimSet().setMiddleName(accessToken.getUserClaimSet().getMiddleName());
+ idToken.getUserClaimSet().setFamilyName(accessToken.getUserClaimSet().getFamilyName());
+ idToken.getUserClaimSet().setName(accessToken.getUserClaimSet().getName());
+ idToken.getUserClaimSet().setNickName(accessToken.getUserClaimSet().getNickName());
+ idToken.getUserClaimSet().setGender(accessToken.getUserClaimSet().getGender());
+ idToken.getUserClaimSet().setPicture(accessToken.getUserClaimSet().getPicture());
+ idToken.getUserClaimSet().setProfile(accessToken.getUserClaimSet().getProfile());
+ idToken.getUserClaimSet().setWebsite(accessToken.getUserClaimSet().getWebsite());
+ idToken.getUserClaimSet().setBirthdate(accessToken.getUserClaimSet().getBirthdate());
+ idToken.getUserClaimSet().setEmail(accessToken.getUserClaimSet().getEmail());
+ idToken.getUserClaimSet().setEmailVerified(accessToken.getUserClaimSet().getEmailVerified());
+ idToken.getUserClaimSet().setLocale(accessToken.getUserClaimSet().getLocale());
+ idToken.getUserClaimSet().setFormattedAddress(accessToken.getUserClaimSet().getFormattedAddress());
+ idToken.getUserClaimSet().setAddress(accessToken.getUserClaimSet().getAddress());
+ idToken.getUserClaimSet().setStreetAddress(accessToken.getUserClaimSet().getStreetAddress());
+ idToken.getUserClaimSet().setLocality(accessToken.getUserClaimSet().getLocality());
+ idToken.getUserClaimSet().setRegion(accessToken.getUserClaimSet().getRegion());
+ idToken.getUserClaimSet().setPostalCode(accessToken.getUserClaimSet().getPostalCode());
+ idToken.getUserClaimSet().setCountry(accessToken.getUserClaimSet().getCountry());
+ idToken.getUserClaimSet().setPhoneNumber(accessToken.getUserClaimSet().getPhoneNumber());
+ idToken.getUserClaimSet().setPhoneNumberVerified(accessToken.getUserClaimSet().getPhoneNumberVerified());
+ idToken.getUserClaimSet().setZoneinfo(accessToken.getUserClaimSet().getZoneinfo());
return this;
}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java b/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java
new file mode 100644
index 0000000..5e69d05
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/UserInfoService.java
@@ -0,0 +1,150 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.protocol.oidc;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.HttpResponse;
+import org.jboss.resteasy.spi.UnauthorizedException;
+import org.keycloak.ClientConnection;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventBuilder;
+import org.keycloak.events.EventType;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.UserClaimSet;
+import org.keycloak.services.managers.AppAuthManager;
+import org.keycloak.services.managers.EventsManager;
+import org.keycloak.services.resources.Cors;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+/**
+ * @author pedroigor
+ */
+public class UserInfoService {
+
+ @Context
+ private HttpRequest request;
+
+ @Context
+ private HttpResponse response;
+
+ @Context
+ private KeycloakSession session;
+
+ @Context
+ private ClientConnection clientConnection;
+
+ private final TokenManager tokenManager;
+ private final AppAuthManager appAuthManager;
+ private final OpenIDConnectService openIdConnectService;
+ private final RealmModel realmModel;
+
+ public UserInfoService(OpenIDConnectService openIDConnectService) {
+ this.realmModel = openIDConnectService.getRealm();
+
+ if (this.realmModel == null) {
+ throw new RuntimeException("Null realm.");
+ }
+
+ this.tokenManager = openIDConnectService.getTokenManager();
+
+ if (this.tokenManager == null) {
+ throw new RuntimeException("Null token manager.");
+ }
+
+ this.openIdConnectService = openIDConnectService;
+ this.appAuthManager = new AppAuthManager();
+ }
+
+ @Path("/")
+ @OPTIONS
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response issueUserInfoPreflight() {
+ return Cors.add(this.request, Response.ok()).auth().preflight().build();
+ }
+
+ @Path("/")
+ @GET
+ @NoCache
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response issueUserInfoGet(@Context final HttpHeaders headers) {
+ String accessToken = this.appAuthManager.extractAuthorizationHeaderToken(headers);
+ return issueUserInfo(accessToken);
+ }
+
+ @Path("/")
+ @POST
+ @NoCache
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response issueUserInfoPost(@FormParam("access_token") String accessToken) {
+ return issueUserInfo(accessToken);
+ }
+
+ private Response issueUserInfo(String token) {
+ try {
+ EventBuilder event = new EventsManager(this.realmModel, this.session, this.clientConnection).createEventBuilder()
+ .event(EventType.USER_INFO_REQUEST)
+ .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN);
+
+ Response validationResponse = this.openIdConnectService.validateAccessToken(token);
+
+ if (!AccessToken.class.isInstance(validationResponse.getEntity())) {
+ event.error(EventType.USER_INFO_REQUEST.name());
+ return Response.fromResponse(validationResponse).status(Status.FORBIDDEN).build();
+ }
+
+ AccessToken accessToken = (AccessToken) validationResponse.getEntity();
+ UserSessionModel userSession = session.sessions().getUserSession(realmModel, accessToken.getSessionState());
+ ClientModel clientModel = realmModel.findClient(accessToken.getIssuedFor());
+ UserModel userModel = userSession.getUser();
+ UserClaimSet userInfo = new UserClaimSet();
+
+ this.tokenManager.initClaims(userInfo, clientModel, userModel);
+
+ event
+ .detail(Details.USERNAME, userModel.getUsername())
+ .client(clientModel)
+ .session(userSession)
+ .user(userModel)
+ .success();
+
+ return Cors.add(request, Response.ok(userInfo)).auth().allowedOrigins(accessToken).build();
+ } catch (Exception e) {
+ throw new UnauthorizedException("Could not retrieve user info.", e);
+ }
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 40093ca..51df254 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -483,10 +483,6 @@ public class AuthenticationManager {
return AuthenticationStatus.INVALID_USER;
}
- if (!user.isEnabled()) {
- return AuthenticationStatus.ACCOUNT_DISABLED;
- }
-
Set<String> types = new HashSet<String>();
for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
@@ -522,6 +518,10 @@ public class AuthenticationManager {
return AuthenticationStatus.INVALID_CREDENTIALS;
}
+ if (!user.isEnabled()) {
+ return AuthenticationStatus.ACCOUNT_DISABLED;
+ }
+
if (user.isTotp() && totp == null) {
return AuthenticationStatus.MISSING_TOTP;
}
@@ -540,6 +540,9 @@ public class AuthenticationManager {
if (!session.users().validCredentials(realm, user, UserCredentialModel.secret(secret))) {
return AuthenticationStatus.INVALID_CREDENTIALS;
}
+ if (!user.isEnabled()) {
+ return AuthenticationStatus.ACCOUNT_DISABLED;
+ }
if (!user.getRequiredActions().isEmpty()) {
return AuthenticationStatus.ACTIONS_REQUIRED;
} else {
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index 4f462e0..84f7cdb 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -826,7 +826,10 @@ public class LoginActionsService {
event.error(Errors.USER_NOT_FOUND);
} else if(!user.isEnabled()) {
event.user(user).error(Errors.USER_DISABLED);
- } else {
+ }
+ else if(user.getEmail() == null || user.getEmail().trim().length() == 0) {
+ event.user(user).error(Errors.INVALID_EMAIL);
+ } else{
event.user(user);
UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "form", false);
diff --git a/services/src/main/java/org/keycloak/services/resources/ServerVersionResource.java b/services/src/main/java/org/keycloak/services/resources/ServerVersionResource.java
index ad703f9..4bf4b2f 100755
--- a/services/src/main/java/org/keycloak/services/resources/ServerVersionResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/ServerVersionResource.java
@@ -1,12 +1,19 @@
package org.keycloak.services.resources;
+import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.Version;
import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -15,10 +22,26 @@ import javax.ws.rs.core.MediaType;
@Path("/version")
public class ServerVersionResource {
+ protected static final Logger logger = Logger.getLogger(ServerVersionResource.class);
+
+ @Context
+ protected HttpRequest request;
+
+ @Context
+ protected HttpResponse response;
+
+ @OPTIONS
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getVersionPreflight() {
+ logger.debugv("cors request from: {0}", request.getHttpHeaders().getRequestHeaders().getFirst("Origin"));
+ return Cors.add(request, Response.ok()).allowedMethods("GET").auth().preflight().build();
+ }
+
@GET
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public Version getVersion() {
+ Cors.add(request).allowedOrigins("*").allowedMethods("GET").auth().build(response);
return Version.SINGLETON;
}
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenantServlet.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenantServlet.java
index 5e04cf2..1501f04 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenantServlet.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/MultiTenantServlet.java
@@ -16,13 +16,14 @@
*/
package org.keycloak.testsuite.adapter;
-import java.io.IOException;
-import java.io.PrintWriter;
+import org.keycloak.KeycloakSecurityContext;
+
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.keycloak.KeycloakSecurityContext;
+import java.io.IOException;
+import java.io.PrintWriter;
/**
*
@@ -37,7 +38,7 @@ public class MultiTenantServlet extends HttpServlet {
KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
pw.print("Username: ");
- pw.println(context.getIdToken().getPreferredUsername());
+ pw.println(context.getIdToken().getUserClaimSet().getPreferredUsername());
pw.print("<br/>Realm: ");
pw.println(context.getRealm());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index 0bb825f..3741c30 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -119,6 +119,62 @@ public class LoginTest {
}
@Test
+ public void loginInvalidPasswordDisabledUser() {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ session.users().getUserByUsername("login-test", appRealm).setEnabled(false);
+ }
+ });
+
+ try {
+ loginPage.open();
+ loginPage.login("login-test", "invalid");
+
+ loginPage.assertCurrent();
+
+ Assert.assertEquals("Invalid username or password.", loginPage.getError());
+
+ events.expectLogin().user(userId).session((String) null).error("invalid_user_credentials").detail(Details.USERNAME, "login-test").removeDetail(Details.CODE_ID).assertEvent();
+ } finally {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ session.users().getUserByUsername("login-test", appRealm).setEnabled(true);
+ }
+ });
+ }
+ }
+
+ @Test
+ public void loginDisabledUser() {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ session.users().getUserByUsername("login-test", appRealm).setEnabled(false);
+ }
+ });
+
+ try {
+ loginPage.open();
+ loginPage.login("login-test", "password");
+
+ loginPage.assertCurrent();
+
+ Assert.assertEquals("Account is disabled, contact admin", loginPage.getError());
+
+ events.expectLogin().user(userId).session((String) null).error("user_disabled").detail(Details.USERNAME, "login-test").removeDetail(Details.CODE_ID).assertEvent();
+ } finally {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ session.users().getUserByUsername("login-test", appRealm).setEnabled(true);
+ }
+ });
+ }
+ }
+
+ @Test
public void loginInvalidUsername() {
loginPage.open();
loginPage.login("invalid", "password");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 878a2e4..07b24d7 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -279,6 +279,44 @@ public class ResetPasswordTest {
resetPasswordPage.changePassword("login-test");
+ resetPasswordPage.assertCurrent();
+
+ Assert.assertEquals("You should receive an email shortly with further instructions.", resetPasswordPage.getSuccessMessage());
+
+ Thread.sleep(1000);
+
+ Assert.assertEquals(0, greenMail.getReceivedMessages().length);
+
+ events.expectRequiredAction(EventType.SEND_RESET_PASSWORD_ERROR).session((String) null).user(userId).detail(Details.USERNAME, "login-test").removeDetail(Details.CODE_ID).error("invalid_email").assertEvent();
+ } finally {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ session.users().getUserByUsername("login-test", appRealm).setEmail(email[0]);
+ }
+ });
+ }
+ }
+
+ @Test
+ public void resetPasswordWrongSmtp() throws IOException, MessagingException, InterruptedException {
+ final String[] host = new String[1];
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ host[0] = appRealm.getSmtpConfig().get("host");
+ appRealm.getSmtpConfig().put("host", "invalid_host");
+ }
+ });
+
+ try {
+ loginPage.open();
+ loginPage.resetPassword();
+
+ resetPasswordPage.assertCurrent();
+
+ resetPasswordPage.changePassword("login-test");
+
errorPage.assertCurrent();
Assert.assertEquals("Failed to send email, please try again later", errorPage.getError());
@@ -292,7 +330,7 @@ public class ResetPasswordTest {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- session.users().getUserByUsername("login-test", appRealm).setEmail(email[0]);
+ appRealm.getSmtpConfig().put("host",host[0]);
}
});
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java
index 16f00f5..2ff046c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/jaxrs/JaxrsFilterTest.java
@@ -316,8 +316,8 @@ public class JaxrsFilterTest {
// @Test
public void testCxfExample() {
- String uri = "http://localhost:9000/customerservice/customers/123";
- //String uri = "http://localhost:8080/jax_rs_basic_servlet/services/service1/customerservice/customers/123";
+ //String uri = "http://localhost:9000/customerservice/customers/123";
+ String uri = "http://localhost:8080/jax_rs_basic_servlet/services/service1/customerservice/customers/123";
Response resp = client.target(uri).request()
.get();
Assert.assertEquals(resp.getStatus(), 401);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index f0e2339..ed47774 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -142,6 +142,25 @@ public class AccessTokenTest {
}
@Test
+ public void accessTokenInvalidRedirectUri() throws Exception {
+ oauth.doLogin("test-user@localhost", "password");
+
+ Event loginEvent = events.expectLogin().assertEvent();
+ String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+ String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+ oauth.redirectUri("http://invalid");
+
+ AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+ Assert.assertEquals(400, response.getStatusCode());
+ Assert.assertEquals("invalid_grant", response.getError());
+ Assert.assertEquals("Incorrect redirect_uri", response.getErrorDescription());
+
+ events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).assertEvent();
+ }
+
+ @Test
public void accessTokenUserSessionExpired() {
oauth.doLogin("test-user@localhost", "password");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index 330d0bc..7ecd292 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -106,7 +106,7 @@ public class AuthorizationCodeTest {
String title = driver.getTitle();
Assert.assertTrue(title.startsWith("Success code="));
- String code = driver.findElement(By.id(OAuth2Constants.CODE)).getText();
+ String code = driver.findElement(By.id(OAuth2Constants.CODE)).getAttribute("value");
keycloakRule.verifyCode(code);
String codeId = events.expectLogin().detail(Details.REDIRECT_URI, "http://localhost:8081/auth/realms/test/protocol/openid-connect/oauth/oob").assertEvent().getDetails().get(Details.CODE_ID);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
index 1fd282a..b76f76f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
@@ -25,6 +25,7 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.OAuth2Constants;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants;
import org.keycloak.models.RealmModel;
@@ -38,6 +39,8 @@ import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.WebDriver;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
/**
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
@@ -48,19 +51,21 @@ public class OAuthRedirectUriTest {
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
- ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
-
ApplicationModel installedApp = appRealm.addApplication("test-installed");
installedApp.setEnabled(true);
installedApp.addRedirectUri(Constants.INSTALLED_APP_URN);
installedApp.addRedirectUri(Constants.INSTALLED_APP_URL);
+ installedApp.setSecret("password");
ApplicationModel installedApp2 = appRealm.addApplication("test-installed2");
installedApp2.setEnabled(true);
installedApp2.addRedirectUri(Constants.INSTALLED_APP_URL + "/myapp");
+ installedApp2.setSecret("password");
+
ApplicationModel installedApp3 = appRealm.addApplication("test-wildcard");
installedApp3.setEnabled(true);
installedApp3.addRedirectUri("http://example.com/foo/*");
+ installedApp3.setSecret("password");
}
});
@@ -221,7 +226,7 @@ public class OAuthRedirectUriTest {
checkRedirectUri("http://localhost/myapp2", false);
}
- private void checkRedirectUri(String redirectUri, boolean expectValid) {
+ private void checkRedirectUri(String redirectUri, boolean expectValid) throws IOException {
oauth.redirectUri(redirectUri);
oauth.openLoginForm();
@@ -231,6 +236,19 @@ public class OAuthRedirectUriTest {
Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("Invalid redirect_uri.", errorPage.getError());
}
+
+ if (expectValid) {
+ loginPage.login("test-user@localhost", "password");
+
+ String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+ Assert.assertNotNull(code);
+
+ OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
+
+ Assert.assertEquals("Expected success, but got error: " + tokenResponse.getError(), 200, tokenResponse.getStatusCode());
+
+ oauth.doLogout(tokenResponse.getRefreshToken(), "password");
+ }
}
}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
new file mode 100755
index 0000000..2828f8d
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -0,0 +1,129 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.oidc;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.OpenIDConnectService;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.UserInfo;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.keycloak.util.BasicAuthHelper;
+import org.openqa.selenium.WebDriver;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriBuilder;
+import java.net.URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * @author pedroigor
+ */
+public class UserInfoTest {
+
+ private static RealmModel realm;
+
+ @ClassRule
+ public static KeycloakRule keycloakRule = new KeycloakRule();
+
+ @Rule
+ public WebRule webRule = new WebRule(this);
+
+ @WebResource
+ protected WebDriver driver;
+
+ @Test
+ public void testSuccessfulUserInfoRequest() throws Exception {
+ Client client = ClientBuilder.newClient();
+ UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
+ URI grantUri = OpenIDConnectService.grantAccessTokenUrl(builder).build("test");
+ WebTarget grantTarget = client.target(grantUri);
+ AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(grantTarget);
+ Response response = executeUserInfoRequest(accessTokenResponse.getToken());
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+ UserInfo userInfo = response.readEntity(UserInfo.class);
+
+ response.close();
+
+ assertNotNull(userInfo);
+ assertNotNull(userInfo.getSubject());
+ assertEquals("test-user@localhost", userInfo.getEmail());
+ assertEquals("test-user@localhost", userInfo.getPreferredUsername());
+
+ client.close();
+ }
+
+ @Test
+ public void testUnsuccessfulUserInfoRequest() throws Exception {
+ Response response = executeUserInfoRequest("bad");
+
+ response.close();
+
+ assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
+ }
+
+ private AccessTokenResponse executeGrantAccessTokenRequest(WebTarget grantTarget) {
+ String header = BasicAuthHelper.createHeader("test-app", "password");
+ Form form = new Form();
+ form.param("username", "test-user@localhost")
+ .param("password", "password");
+
+ Response response = grantTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, header)
+ .post(Entity.form(form));
+
+ assertEquals(200, response.getStatus());
+
+ AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
+
+ response.close();
+
+ return accessTokenResponse;
+ }
+
+ private Response executeUserInfoRequest(String accessToken) {
+ UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
+ UriBuilder uriBuilder = OpenIDConnectService.tokenServiceBaseUrl(builder);
+ URI userInfoUri = uriBuilder.path(OpenIDConnectService.class, "issueUserInfo").build("test");
+ Client client = ClientBuilder.newClient();
+ WebTarget userInfoTarget = client.target(userInfoUri);
+
+ return userInfoTarget.request()
+ .header(HttpHeaders.AUTHORIZATION, "bearer " + accessToken)
+ .get();
+ }
+}
diff --git a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index 22170ee..4b87597 100755
--- a/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty91/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -21,49 +21,23 @@
*/
package org.keycloak.testsuite;
-import org.eclipse.jetty.security.ConstraintMapping;
-import org.eclipse.jetty.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass;
-import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.OAuth2Constants;
-import org.keycloak.adapters.jetty.AbstractKeycloakJettyAuthenticator;
-import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.protocol.oidc.OpenIDConnectService;
-import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.adapter.AdapterTestStrategy;
-import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
-import org.keycloak.testsuite.rule.WebResource;
-import org.keycloak.testsuite.rule.WebRule;
-import org.keycloak.testutils.KeycloakServer;
-import org.openqa.selenium.WebDriver;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.UriBuilder;
+
import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
import java.net.URL;
-import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
diff --git a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
index e965ea6..ceab804 100755
--- a/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
+++ b/testsuite/jetty/jetty92/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -21,49 +21,23 @@
*/
package org.keycloak.testsuite;
-import org.eclipse.jetty.security.ConstraintMapping;
-import org.eclipse.jetty.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass;
-import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.OAuth2Constants;
-import org.keycloak.adapters.jetty.AbstractKeycloakJettyAuthenticator;
-import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
-import org.keycloak.protocol.oidc.OpenIDConnectService;
-import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.adapter.AdapterTestStrategy;
-import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule;
-import org.keycloak.testsuite.rule.WebResource;
-import org.keycloak.testsuite.rule.WebRule;
-import org.keycloak.testutils.KeycloakServer;
-import org.openqa.selenium.WebDriver;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.core.UriBuilder;
+
import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
import java.net.URL;
-import java.security.Principal;
import java.util.ArrayList;
import java.util.List;