How to add custom field in access token (JWT) generated through keycloack? - spring-boot

I am working on a spring-boot project where we are using keycloak for authorization. I have to update the access-token coming from keycloak with some additional details.
I have tried many jwt libraries and oauth springboot but not able to achieve it

To add claims, you have to do it from authorization-server (Keycloak in your case), not resource-server (REST API) nor client. This is obvious for JWTs (which are sealed with content signed by authorization-server), but should be respected for introspection too.
Keycloak "mapper"
For Keycloak, private claims are added using "mappers". I have a complete sample in this project.
All you have to do is:
pull Keycloak dependencies and add maven shade plugin to your build
<dependencies>
<!-- provided keycloak dependencies -->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<version>${keycloak.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
provide src/main/resources/META-INF/jboss-deployment-structure.xml with this content:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.keycloak.keycloak-services" />
</dependencies>
</deployment>
</jboss-deployment-structure>
provide src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper with a content like (replace with your own mapper implementation):
com.c4_soft.user_proxies.api.keycloak.ProxiesMapper
provide just above referenced mapper implementation using Keycloak base class and interfaces you need (OIDCAccessTokenMapper to add claims to access-tokens is probably a minimum in your case):
public class ProxiesMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper { }
package and deploy to Keycloak providers directory (might need to run keycloak with build arg once as instructed in providers folder README)
configure your new mapper from Keycloak administration UI (for the realm or individual clients)
Parsing private claims in Spring
You can access all claims, including privates ones, from spring default Authentication implementations: JwtAuthenticationToken::getTokenAttributes (for JWT decoder) and BearerTokenAuthentication::getTokenAttributes (for introspection). Both return a Map<String, Object> you can use in security expressions.
You can also provide your own Authentication in place of Spring default ones and parse private claims there (return something more usefull than Object for the claims you use). Switching Authentication implementation is done the same way as switching authorities mapping:
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(...)
or
http.oauth2ResourceServer().opaqueToken().authenticationConverter(...)
I have a set of 3 tutorials which incrementally explain how to easily parse (and use in security expression) such private claims: https://github.com/ch4mpy/spring-addons/tree/master/samples/tutorials
Those tutorials are for servlets. If you are writing reactive applications, follow the tutorials and then refer to one of the samples matching your exact configuration

Related

AWS Lambda in Java: how to call a REST endpoint exposed in API Gateway

I have a REST API exposed on the AWS infrastructure on the behalf of API Gateway. In a Lambda function in Java I need to call the associated endpoints. The AWS documentation recommends to generate a client using the API Gateway console. However, the generated client has several dozens of classes, perhaps even 100 ! Of course, this couldn't be the way.
Did anyone succeed to call API Gateway exposed endpoints using RESTeasy or CXF clients ? Or even Apache HTTP Client ?
Many thanks in advance.
I'm answering my own question. Finally, I confirm that using JAX-RS clients works as expected with API Gateway. In my case, I preferred RESTeasy, but it should work with CXF as well or even with the Apache HTTp Client. Here is what I did:
Maven dependencies:
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-bom</artifactId>
<version>4.4.1.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>4.4.1.Final</version>
<exclusions>
<exclusion>
<groupId>org.jboss.spec.javax.xml.bind</groupId>
<artifactId>jboss-jaxb-api_2.3_spec</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxb-provider</artifactId>
<exclusions>
<exclusion>
<groupId>org.jboss.spec.javax.xml.bind</groupId>
<artifactId>jboss-jaxb-api_2.3_spec</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
</dependency>
...
Please notice the exclusions meant to workaround the maven-shade-plugin which will overload different versions of the same artifacts.
maven-shade-plugin configuration:
...
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>...</finalName>
<createDependencyReducedPom>false</createDependencyReducedPom>
<!-- Using filtering in order to get rid of nasty warnings generated by shading module-info-->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>module-info.class</exclude>
</excludes>
</filter>
</filters>
<!-- Required as per https://stackoverflow.com/questions/24023155-->
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
</transformers>
</configuration>
</plugin>
...
Java client code:
...
private static ResteasyClient client = new ResteasyClientBuilderImpl().httpEngine(new URLConnectionEngine()).build();
private static WebTarget webTarget = client.target("https://...");
...
webTarget.request().post(Entity.entity(..., "application/json"));
...
Please notice that using JAX-RS pure client as below:
...
private static Client client = ClientBuilder.newClient();
...
won't work and will raise the following exception:
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7933f1c0: Failure in SSL library, usually a protocol error
Hence, in order to work around this, I needed to use RESTeasy (non JAX-RS) specific stuff, which isn't good. This is a RESTeasy bug and is supposed to have been solved in 4.5. However, due to some deprecations and refactorings (class ResteasyClientBuilderImpl doesn't exist any more, etc.) I preferred stay with the 4.4.
So, doing like this works as expected, the Lambda functions successfully call the REST endpoints exposed through API Gateway and I don't need to use the huge Java library generated with AWS console.

Adding Spring (Boot?) to existing RESTEasy JAX-RS application

I have an existing Maven project based on JAX-RS using RESTEasy. It works great! It creates a WAR that I deploy to Tomcat running on Ubuntu. It's clean and follows the latest standards. The POM is simple:
...
<packaging>war</packaging>
...
<dependencies>
...
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-servlet-initializer</artifactId>
<version>3.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>3.1.0.Final</version>
</dependency>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
...
I don't need any web.xml because I'm using the latest Java EE annotations:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/")
public class MyRESTApplication extends Application {
final FooResource fooResource = new FooResourceService();
...
#Override
public Set<Object> getSingletons() {
return ImmutableSet.of(fooResource);
}
}
This is all simple and it's working so great! Now I just want a way to easily change FooResource implementations based on the profile --- in other words, wire my singletons. That's where Spring comes in, right? And I've been told that Spring Boot makes Spring even more awesome, and you can use it with anything, and it gives you an actuator that allows you to gain real-time inside on the health of your system.
Unfortunately all the Spring Boot books and tutorials seem to think I'm starting with one of their quick-start applications. But I already have a great, simple application. I just want to:
Get my application wiring, based on profiles, from an external configuration file (not annotations) via Spring.
Get whatever other goodness comes from Spring Boot, because apparently it is awesome and will completely transform my application.
How do I add Spring (or Spring Boot) to this simple little JAX-RS application?
we solved it that way, that we created a singleton spring bean, let's call it ServiceStartupClass, where we register all JAX-RS services.
Here some code snippet how we start our services:
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
#Component
#ApplicationPath("/")
public class ServiceStartupClass extends ResourceConfig {
#PostConstruct
public void startup() {
register(FooResource.class);
...
}
}
If you need any further help, let me know

Not able to retrieve Build info using spring-boot-actuators through /info endpoint

we are trying to take advantage of spring-boot-actuator to retrieve build info through /info endpoint i'm getting empty "{}" object as response these are my pom configurations
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.1.RELEASE</version>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
i made sure build-info. properties is created in my target/META-INF/classes folder through build-info goal
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.4.0.RELEASE</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
please let me know if i'm missing anything. The end point itself seem's to be accessible not sure if i have to do anything else as the documentation say's http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html if build-info properties file is present that build-info properties by default are exposed via /info end point
Note : we are not using application.yml in the project, also we will not be able to upgrage the starter-parent to 1.4.Release at this time
You are only pretending you're using Spring Boot 1.4. Overriding individual versions like you are doing is really an awful idea. Since you haven't changed the parent, you indeed get the starter for 1.4 but the actual actuator module is still 1.3.1. It does not work because the code that detects the build info simply isn't there.
Please perform a proper upgrade to 1.4
If you can only rely on Spring Boot 1.3.1 then you need to follow the documentation for that version. You can see that documentation differs from the Spring Boot 1.4 documentation and as such a different method was made available in Spring Boot 1.4 to expose the build information.

Using Spring Boot 1.3, spring-boot-devtools and Thymeleaf templates won't do live reload when changed in IntelliJ 15

Spring Boot 1.3 introduced spring-boot-devtools to provide similar functionality as Spring Reloaded to reload modified static resource templates (html, js) without having to re-run your application.
I have been using Spring Boot 1.2.7 before and I was able to modify my static resources on the fly without having to restart my Spring Boot application.
Same application is now not reloading my static resources.
I am using IntelliJ 15.1. The application is packaged as a WAR file.
I have the following dependencies in my pom.xml (including others, excluded for not being relevant):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.3.2.RELEASE</version>
</plugin>
</plugins>
</build>
I tried to use spring-boot-maven-plugin with version tag 1.3.2.RELEASE and suddenly changes to my html,js files are visible in browser when the template is saved. It seems that at least the problem is because of the spring-bot-maven-plugin.
I have also set the resource right:
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.html</include>
<include>**/*.properties</include>
</includes>
</resource>
Could somebody please help me resolve this?
Did you make sure you were compiling your project? I know I've needed to do that in boot 1.2.x.
Otherwise, I'd check this duplicate-sounding post:
Using Spring Boot 1.3, spring-boot-devtools and Thymeleaf templates won't do live reload when changed in Netbeans

Spring 4 Java Config Transactions Proxy and Aspecj

I am creating a new project that uses aspectj transactions. It also uses legacy jars that contain services that are using the proxy method where an interface is required.
I am using java config and when I set
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
Then I get the following exception thrown with accessing the proxy style services from the legacy libs:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
If I change to:
#EnableTransactionManagement(mode=AdviceMode.PROXY)
Then I don't get the problem but I can't then use the aspectj style transactions in my new project.
I've tried adding two #EnableTransactionManagement annotations with each adviceMode, but that is not allowed.
Here is the annotated class
#EnableWebMvc
#Configuration
#ComponentScan("com.mydomain")
#EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class ApplicationConfig extends WebMvcConfigurerAdapter {
...
I've also added the aspectj maven plugin to the legacy project in the hope that it would handle the weaving at compile time and thus aspectj transactions would work. But this has not solved the problem.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
Is it possible to have spring deal with both advice modes? How would I do this?
Or is there another way around this problem.
The problem was with the aspectj config on the legacy project.
When I ran mvn compile it became apparent. I had to add the dependency:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
That got it working when compiled using maven, but I it would still not work in eclipse. I had to right click on the legacy project in eclipse:
Configure>Convert to Aspectj Project
Then I could deploy from eclipse and I had aspectj transactional support in the legacy jars.

Resources