Merge pull request #918 from mposolda/master

Fuse/Karaf adapter, demo example and documentation
This commit is contained in:
Marek Posolda 2015-01-15 20:32:44 +01:00
commit ba0dc06252
77 changed files with 2857 additions and 117 deletions

View file

@ -11,11 +11,19 @@
<artifactId>keycloak-core</artifactId> <artifactId>keycloak-core</artifactId>
<name>Keycloak Core</name> <name>Keycloak Core</name>
<packaging>jar</packaging>
<description/> <description/>
<properties> <properties>
<timestamp>${maven.build.timestamp}</timestamp> <timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format> <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> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
@ -60,6 +68,39 @@
<target>${maven.compiler.target}</target> <target>${maven.compiler.target}</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -93,6 +93,12 @@
<exclude name="**/README.md"/> <exclude name="**/README.md"/>
</fileset> </fileset>
</copy> </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"/> <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/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"/> <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"/>

View file

@ -1,15 +1,53 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<features xmlns="http://karaf.apache.org/xmlns/features/v1.0.0" name="keycloak-${project.version}"> <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)"> <feature name="keycloak-adapter-core" version="${project.version}" resolver="(obr)">
<details>The keycloak core adapter stuff</details> <details>The keycloak adapter core stuff</details>
<bundle>mvn:org.keycloak/keycloak-osgi-core-adapter/${project.version}</bundle> <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>
<feature name="keycloak-jaas" version="${project.version}" resolver="(obr)"> <feature name="keycloak-jaas" version="${project.version}" resolver="(obr)">
<details>The keycloak JAAS configuration</details> <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> <bundle>mvn:org.keycloak/keycloak-osgi-jaas/${project.version}</bundle>
</feature> </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> </features>

View file

@ -7,7 +7,7 @@
<version>1.2.0.Beta1-SNAPSHOT</version> <version>1.2.0.Beta1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath> <relativePath>../../../pom.xml</relativePath>
</parent> </parent>
<name>Keycloak OSGI JAAS</name> <name>Keycloak OSGI JAAS Realm Configuration</name>
<description/> <description/>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -27,7 +27,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-osgi-core-adapter</artifactId> <artifactId>keycloak-adapter-core</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
@ -53,7 +53,7 @@
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency> <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
<Embed-Transitive>false</Embed-Transitive> <Embed-Transitive>false</Embed-Transitive>
<Bundle-ClassPath>.</Bundle-ClassPath> --> <Bundle-ClassPath>.</Bundle-ClassPath> -->
<Bundle-Name>${project.description}</Bundle-Name> <Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package> <Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package> <Export-Package>${keycloak.osgi.export}</Export-Package>

View file

@ -17,7 +17,7 @@
<modules> <modules>
<module>features</module> <module>features</module>
<module>jaas</module> <module>jaas</module>
<module>core-adapter</module> <module>thirdparty</module>
</modules> </modules>
</project> </project>

View file

@ -7,17 +7,18 @@
<version>1.2.0.Beta1-SNAPSHOT</version> <version>1.2.0.Beta1-SNAPSHOT</version>
<relativePath>../../../pom.xml</relativePath> <relativePath>../../../pom.xml</relativePath>
</parent> </parent>
<name>Keycloak OSGI Core Adapter Integration</name>
<description/> <name>Keycloak OSGI Thirdparty</name>
<description>Keycloak OSGI bundling for 3rd party libs without OSGI headers in manifest</description>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-osgi-core-adapter</artifactId> <artifactId>keycloak-osgi-thirdparty</artifactId>
<packaging>bundle</packaging> <packaging>bundle</packaging>
<properties> <properties>
<keycloak.osgi.export> <keycloak.osgi.export>
org.keycloak.adapters.jaas, net.iharder;version="${base64.version}",
org.keycloak.adapters org.apache.http.*;version=${keycloak.apache.httpcomponents.version}
</keycloak.osgi.export> </keycloak.osgi.export>
<keycloak.osgi.import> <keycloak.osgi.import>
*;resolution:=optional *;resolution:=optional
@ -26,45 +27,19 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>net.iharder</groupId>
<artifactId>keycloak-core</artifactId> <artifactId>base64</artifactId>
<version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>keycloak-adapter-core</artifactId> <artifactId>httpcore</artifactId>
<version>${project.version}</version> <version>${keycloak.apache.httpcomponents.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>${keycloak.apache.httpcomponents.version}</version> <version>${keycloak.apache.httpcomponents.version}</version>
</dependency> </dependency>
<dependency>
<groupId>net.iharder</groupId>
<artifactId>base64</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-xc</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -84,14 +59,14 @@
</executions> </executions>
<configuration> <configuration>
<instructions> <instructions>
<Embed-Dependency>*;scope=compile|runtime;artifactId=!keycloak-adapter-core</Embed-Dependency> <Embed-Dependency>*;scope=compile|runtime;artifactId=!httpclient|httpcore|base64</Embed-Dependency>
<Embed-Transitive>true</Embed-Transitive> <Embed-Transitive>true</Embed-Transitive>
<Bundle-ClassPath>.</Bundle-ClassPath> <Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-Name>${project.description}</Bundle-Name> <Bundle-Name>${project.name}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName> <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
<Import-Package>${keycloak.osgi.import}</Import-Package> <Import-Package>${keycloak.osgi.import}</Import-Package>
<Export-Package>${keycloak.osgi.export}</Export-Package> <Export-Package>${keycloak.osgi.export}</Export-Package>
<Implementation-Title>keycloak</Implementation-Title> <Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version> <Implementation-Version>${project.version}</Implementation-Version>
</instructions> </instructions>
</configuration> </configuration>

View file

@ -14,9 +14,11 @@
<!ENTITY TomcatAdapter SYSTEM "modules/tomcat-adapter.xml"> <!ENTITY TomcatAdapter SYSTEM "modules/tomcat-adapter.xml">
<!ENTITY Jetty9Adapter SYSTEM "modules/jetty9-adapter.xml"> <!ENTITY Jetty9Adapter SYSTEM "modules/jetty9-adapter.xml">
<!ENTITY Jetty8Adapter SYSTEM "modules/jetty8-adapter.xml"> <!ENTITY Jetty8Adapter SYSTEM "modules/jetty8-adapter.xml">
<!ENTITY FuseAdapter SYSTEM "modules/fuse-adapter.xml">
<!ENTITY InstalledApplications SYSTEM "modules/installed-applications.xml"> <!ENTITY InstalledApplications SYSTEM "modules/installed-applications.xml">
<!ENTITY Logout SYSTEM "modules/logout.xml"> <!ENTITY Logout SYSTEM "modules/logout.xml">
<!ENTITY SAML SYSTEM "modules/saml.xml"> <!ENTITY SAML SYSTEM "modules/saml.xml">
<!ENTITY JAAS SYSTEM "modules/jaas.xml">
<!ENTITY SocialConfig SYSTEM "modules/social-config.xml"> <!ENTITY SocialConfig SYSTEM "modules/social-config.xml">
<!ENTITY SocialFacebook SYSTEM "modules/social-facebook.xml"> <!ENTITY SocialFacebook SYSTEM "modules/social-facebook.xml">
<!ENTITY SocialGitHub SYSTEM "modules/social-github.xml"> <!ENTITY SocialGitHub SYSTEM "modules/social-github.xml">
@ -91,10 +93,12 @@ This one is short
&TomcatAdapter; &TomcatAdapter;
&Jetty9Adapter; &Jetty9Adapter;
&Jetty8Adapter; &Jetty8Adapter;
&FuseAdapter;
&JavascriptAdapter; &JavascriptAdapter;
&InstalledApplications; &InstalledApplications;
&Logout; &Logout;
&MultiTenancy; &MultiTenancy;
&JAAS;
</chapter> </chapter>
<chapter> <chapter>

View file

@ -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>

View file

@ -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>

View file

@ -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` 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`

132
examples/fuse/README.md Normal file
View file

@ -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).

View file

@ -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>

View file

@ -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());
}
}

View file

@ -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&amp;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>

View file

@ -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>

View file

@ -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();
}
}

View file

@ -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();
}
}
}

View file

@ -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>

View file

@ -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"
}
}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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>

View file

@ -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>

View file

@ -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"
}
}

View file

@ -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>

View file

@ -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;
}

View file

@ -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";
}
}
}

View file

@ -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;
}
}

View file

@ -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>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}

View file

@ -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>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="ssn" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}

View file

@ -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();
}
}

View file

@ -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>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}

View file

@ -0,0 +1 @@
package org.keycloak.example.ws.types;

View file

@ -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>

View file

@ -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>

View file

@ -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>

37
examples/fuse/pom.xml Normal file
View file

@ -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>

View file

@ -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>

View file

@ -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;
}
}
}

View file

@ -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>

View file

@ -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>

View file

@ -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"
}
}

View file

@ -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
}
]
}

View file

@ -32,5 +32,6 @@
<module>js-console</module> <module>js-console</module>
<module>multi-tenant</module> <module>multi-tenant</module>
<module>basic-auth</module> <module>basic-auth</module>
<module>fuse</module>
</modules> </modules>
</project> </project>

View file

@ -13,6 +13,17 @@
<name>Keycloak Adapter Core</name> <name>Keycloak Adapter Core</name>
<description/> <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> <dependencies>
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
@ -73,6 +84,39 @@
<target>${maven.compiler.target}</target> <target>${maven.compiler.target}</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -6,7 +6,7 @@ import org.keycloak.VerificationException;
/** /**
* Login module, which allows to authenticate Keycloak access token in environments, which rely on JAAS * Login module, which allows to authenticate Keycloak access token in environments, which rely on JAAS
* <p/> * <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> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */

View file

@ -74,7 +74,6 @@
<dependency> <dependency>
<groupId>org.osgi</groupId> <groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId> <artifactId>org.osgi.core</artifactId>
<version>4.3.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View file

@ -13,6 +13,15 @@
<name>Keycloak Jetty Core Integration</name> <name>Keycloak Jetty Core Integration</name>
<properties> <properties>
<jetty9.version>8.1.16.v20140903</jetty9.version> <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> </properties>
<description /> <description />
@ -94,6 +103,39 @@
<target>1.6</target> <target>1.6</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -1,8 +1,6 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext; import org.keycloak.KeycloakSecurityContext;
@ -12,7 +10,6 @@ import org.keycloak.adapters.KeycloakAccount;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext; import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.adapters.RequestAuthenticator; import org.keycloak.adapters.RequestAuthenticator;
import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;

View file

@ -1,6 +1,5 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.apache.http.HttpVersion;
import org.eclipse.jetty.security.DefaultUserIdentity; import org.eclipse.jetty.security.DefaultUserIdentity;
import org.eclipse.jetty.security.ServerAuthException; import org.eclipse.jetty.security.ServerAuthException;
import org.eclipse.jetty.security.UserAuthentication; import org.eclipse.jetty.security.UserAuthentication;
@ -162,8 +161,19 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
@SuppressWarnings("UseSpecificCatch") @SuppressWarnings("UseSpecificCatch")
public void initializeKeycloak() { public void initializeKeycloak() {
nodesRegistrationManagement = new NodesRegistrationManagement(); nodesRegistrationManagement = new NodesRegistrationManagement();
String contextPath = ContextHandler.getCurrentContext().getContextPath();
ServletContext theServletContext = ContextHandler.getCurrentContext().getContext(contextPath); ServletContext theServletContext = null;
ContextHandler.Context currentContext = ContextHandler.getCurrentContext();
if (currentContext != null) {
String contextPath = currentContext.getContextPath();
if ("".equals(contextPath)) {
// This could be the case in osgi environment when deploying apps through pax whiteboard extension.
theServletContext = currentContext;
} else {
theServletContext = currentContext.getContext(contextPath);
}
}
// Jetty 9.1.x servlet context will be null :( // Jetty 9.1.x servlet context will be null :(
if (configResolver == null && theServletContext != null) { if (configResolver == null && theServletContext != null) {

View file

@ -1,4 +1,4 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;

View file

@ -1,4 +1,4 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.keycloak.KeycloakSecurityContext; import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.HttpFacade; import org.keycloak.adapters.HttpFacade;

View file

@ -1,4 +1,4 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;

View file

@ -1,4 +1,4 @@
package org.keycloak.adapters.jetty; package org.keycloak.adapters.jetty.core;
import org.eclipse.jetty.server.SessionManager; import org.eclipse.jetty.server.SessionManager;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;

View file

@ -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);
}
}
}

View file

@ -13,6 +13,14 @@
<name>Keycloak Jetty 8.1.x Integration</name> <name>Keycloak Jetty 8.1.x Integration</name>
<properties> <properties>
<jetty9.version>8.1.16.v20140903</jetty9.version> <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> </properties>
<description /> <description />
@ -99,6 +107,39 @@
<target>1.6</target> <target>1.6</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -4,6 +4,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap; import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;

View file

@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;

View file

@ -13,6 +13,15 @@
<name>Keycloak Jetty 9.1.x Integration</name> <name>Keycloak Jetty 9.1.x Integration</name>
<properties> <properties>
<jetty9.version>9.1.5.v20140505</jetty9.version> <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> </properties>
<description /> <description />
@ -113,6 +122,39 @@
<target>1.6</target> <target>1.6</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -5,6 +5,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap; import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;

View file

@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;

View file

@ -13,6 +13,15 @@
<name>Keycloak Jetty 9.2.x Integration</name> <name>Keycloak Jetty 9.2.x Integration</name>
<properties> <properties>
<jetty9.version>9.2.4.v20141103</jetty9.version> <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> </properties>
<description /> <description />
@ -99,6 +108,39 @@
<target>1.6</target> <target>1.6</target>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>

View file

@ -5,10 +5,10 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiMap;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractJettySessionTokenStore;
import org.keycloak.util.MultivaluedHashMap; import org.keycloak.util.MultivaluedHashMap;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -6,6 +6,7 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.keycloak.adapters.AdapterTokenStore; import org.keycloak.adapters.AdapterTokenStore;
import org.keycloak.adapters.KeycloakDeployment; import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;

View file

@ -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>

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -28,5 +28,6 @@
<module>js</module> <module>js</module>
<module>installed</module> <module>installed</module>
<module>admin-client</module> <module>admin-client</module>
<module>osgi-adapter</module>
</modules> </modules>
</project> </project>

20
pom.xml
View file

@ -13,6 +13,7 @@
<properties> <properties>
<aesh.version>0.33.12</aesh.version> <aesh.version>0.33.12</aesh.version>
<base64.version>2.3.8</base64.version>
<bouncycastle.version>1.46</bouncycastle.version> <bouncycastle.version>1.46</bouncycastle.version>
<jackson.version>1.9.9</jackson.version> <jackson.version>1.9.9</jackson.version>
<keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version> <keycloak.apache.httpcomponents.version>4.2.1</keycloak.apache.httpcomponents.version>
@ -48,6 +49,8 @@
<infinispan.version>6.0.2.Final</infinispan.version> <infinispan.version>6.0.2.Final</infinispan.version>
<liquibase.version>3.2.2</liquibase.version> <liquibase.version>3.2.2</liquibase.version>
<jetty9.version>9.1.0.v20131115</jetty9.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-plugin -->
<maven.compiler.target>1.6</maven.compiler.target> <maven.compiler.target>1.6</maven.compiler.target>
@ -139,7 +142,7 @@
<dependency> <dependency>
<groupId>net.iharder</groupId> <groupId>net.iharder</groupId>
<artifactId>base64</artifactId> <artifactId>base64</artifactId>
<version>2.3.8</version> <version>${base64.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.mail</groupId> <groupId>javax.mail</groupId>
@ -508,6 +511,21 @@
<artifactId>liquibase-core</artifactId> <artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version> <version>${liquibase.version}</version>
</dependency> </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> </dependencies>
</dependencyManagement> </dependencyManagement>

View file

@ -316,8 +316,8 @@ public class JaxrsFilterTest {
// @Test // @Test
public void testCxfExample() { public void testCxfExample() {
String uri = "http://localhost:9000/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"; String uri = "http://localhost:8080/jax_rs_basic_servlet/services/service1/customerservice/customers/123";
Response resp = client.target(uri).request() Response resp = client.target(uri).request()
.get(); .get();
Assert.assertEquals(resp.getStatus(), 401); Assert.assertEquals(resp.getStatus(), 401);

View file

@ -21,49 +21,23 @@
*/ */
package org.keycloak.testsuite; 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.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection; 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.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; 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.KeycloakSession;
import org.keycloak.models.RealmModel; 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.services.managers.RealmManager;
import org.keycloak.testsuite.adapter.AdapterTestStrategy; import org.keycloak.testsuite.adapter.AdapterTestStrategy;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; 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.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL; import java.net.URL;
import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View file

@ -21,49 +21,23 @@
*/ */
package org.keycloak.testsuite; 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.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection; 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.eclipse.jetty.webapp.WebAppContext;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; 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.KeycloakSession;
import org.keycloak.models.RealmModel; 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.services.managers.RealmManager;
import org.keycloak.testsuite.adapter.AdapterTestStrategy; import org.keycloak.testsuite.adapter.AdapterTestStrategy;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.AbstractKeycloakRule; 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.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL; import java.net.URL;
import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;