Skip to content

Instantly share code, notes, and snippets.

@rasheedamir
Forked from thomasdarimont/App.java
Created August 23, 2017 05:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rasheedamir/c87b043fceec6590e8cc8b379da33d59 to your computer and use it in GitHub Desktop.
Save rasheedamir/c87b043fceec6590e8cc8b379da33d59 to your computer and use it in GitHub Desktop.
Example for using the keycloak Spring Security Adapter (2.4.0.Final) with a Bearer-only Spring Boot App deployed in JBoss EAP
package de.tdlabs.examples;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class App extends SpringBootServletInitializer {
/**
* Initializes this application when running as a standalone application.
*/
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
/**
* Initializes this application when running in a servlet container (e.g. Tomcat)
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(App.class);
}
}
package de.tdlabs.examples;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/customers")
//@CacheControl(policy = CachePolicy.NO_CACHE)
public class CustomerApiController {
private static final Logger log = LoggerFactory.getLogger(CustomerApiController.class);
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<String> getCustomers() {
log.info("Returning customer list.");
return Arrays.asList("Scott Rossillo", "Kyung Lee", "Keith Leggins", "Ben Loy");
}
}

Query /customers endpoint on database service without any authentication

$ curl -v http://localhost:8080/keycloak-example-spring-security-war-0.0.1.BUILD-SNAPSHOT/customers
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /keycloak-example-spring-security-war-0.0.1.BUILD-SNAPSHOT/customers HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.46.0
> Accept: */*
> 
< HTTP/1.1 401 Unauthorized
< Expires: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< X-Powered-By: Undertow/1
< Server: JBoss-EAP/7
< X-XSS-Protection: 1; mode=block
< Pragma: no-cache
< X-Frame-Options: DENY
< Date: Wed, 23 Nov 2016 22:25:33 GMT
< Connection: keep-alive
< WWW-Authenticate: Bearer realm="Unknown"
< X-Content-Type-Options: nosniff
< Transfer-Encoding: chunked
< Content-Type: application/json;charset=UTF-8
< 
* Connection #0 to host localhost left intact
{"timestamp":1479939933320,"status":401,"error":"Unauthorized","message":"Unauthorized","path":"/keycloak-example-spring-security-war-0.0.1.BUILD-SNAPSHOT/customers"}%  

Retrieve access token via curl from a dummy confidential client

KC_REALM=spring-security-adapter-test
KC_USERNAME=tester
KC_PASSWORD=test
KC_CLIENT=dummy
KC_CLIENT_SECRET=98732edc-573e-4a45-8fbc-0feee1ebcccb
KC_URL="http://localhost:8180/auth"

# Request Tokens for credentials
KC_RESPONSE=$( \
   curl -k -v \
        -d "username=$KC_USERNAME" \
        -d "password=$KC_PASSWORD" \
        -d 'grant_type=password' \
        -d "client_id=$KC_CLIENT" \
        -d "client_secret=$KC_CLIENT_SECRET" \
        "$KC_URL/realms/$KC_REALM/protocol/openid-connect/token" \
    | jq .
)

KC_ACCESS_TOKEN=$(echo $KC_RESPONSE| jq -r .access_token)
KC_ID_TOKEN=$(echo $KC_RESPONSE| jq -r .id_token)
KC_REFRESH_TOKEN=$(echo $KC_RESPONSE| jq -r .refresh_token)

Query /customers endpoint on database service with a valid access token

$ curl -H "Authorization: Bearer $KC_ACCESS_TOKEN" -v http://localhost:8080/keycloak-example-spring-security-war-0.0.1.BUILD-SNAPSHOT/customers
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /keycloak-example-spring-security-war-0.0.1.BUILD-SNAPSHOT/customers HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.46.0
> Accept: */*
> Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoS19sRGJGUzFVekN0VnY1cE5oSVRXYy1nV1VIcENRelB1Ylp4NlRNdk1jIn0.eyJqdGkiOiI1MjA3YmYzMC05YTYwLTRjM2MtODE2OS02YzEzMjViMjFiYmUiLCJleHAiOjE0Nzk5NDAxNzUsIm5iZiI6MCwiaWF0IjoxNDc5OTM5ODc1LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvc3ByaW5nLXNlY3VyaXR5LWFkYXB0ZXItdGVzdCIsImF1ZCI6ImR1bW15Iiwic3ViIjoiYWZjZjRmYWMtYWNlYy00MzU5LWJhZjYtNjJkMTZiMGFiZmVjIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZHVtbXkiLCJhdXRoX3RpbWUiOjAsInNlc3Npb25fc3RhdGUiOiI4NzNmZTg2NS05ZjMzLTRhZDQtODdjYS03NzllOGExNzcwODkiLCJhY3IiOiIxIiwiY2xpZW50X3Nlc3Npb24iOiJhYjlhMzExNy04NGI5LTQ5MTEtYjJmZS04MjJlNmFlZDM3ODYiLCJhbGxvd2VkLW9yaWdpbnMiOltdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJkYXRhYmFzZS1jbGllbnQiOnsicm9sZXMiOlsidXNlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsInZpZXctcHJvZmlsZSJdfX0sIm5hbWUiOiJUaGVvIFRlc3RlciIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3RlciIsImdpdmVuX25hbWUiOiJUaGVvIiwiZmFtaWx5X25hbWUiOiJUZXN0ZXIifQ.B8mTvA7YiaFj3vAwrwXM_7FVlPUy71bmDv32Fb0adh1wkFtWPR05HEdKklF_zxeeACYwy2jZ1iikeJHLAxHu7GAzT7DY1EfqStsbHMkgMNVJ-eX6KYQk31_paKpV-WuYFjg6X9joh2nisf9f0DWpcLojKDy_ORpvhWOUgKMUiMZLex3dHWhT5aAg-qtLZwH7VKxjQId84jaLGUjoZfZIFMsG49AJOvUAVTTvsd1et4SO_PaK8qdCMu0feHoQsP1irT2c18zHwMGmC4E6E7pG-jTl7bvDp7TprGfyfIlWkwF8iw29BvqCmRhnWvtUC4cdENQVjZsrAhRsA6S5EkLn4w
> 
< HTTP/1.1 200 OK
< Expires: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< X-Powered-By: Undertow/1
< Server: JBoss-EAP/7
< X-XSS-Protection: 1; mode=block
< Pragma: no-cache
< X-Frame-Options: DENY
< Date: Wed, 23 Nov 2016 22:26:07 GMT
< Connection: keep-alive
< X-Content-Type-Options: nosniff
< Transfer-Encoding: chunked
< Content-Type: application/json;charset=UTF-8
< 
* Connection #0 to host localhost left intact
["Scott Rossillo","Kyung Lee","Keith Leggins","Ben Loy"]%                                                                                                                         
{
"realm": "spring-security-adapter-test",
"bearer-only": true,
"auth-server-url": "http://localhost:8180/auth",
"ssl-required": "external",
"resource": "database-client",
"use-resource-role-mappings": true
}
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.tdlabs</groupId>
<artifactId>keycloak-example-spring-security-war</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<packaging>war</packaging>
<name>keycloak-example-spring-security-war</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>2.3.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package de.tdlabs.examples;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
/**
* Application security configuration.
*
* @author Scott Rossillo
*/
@Configuration
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
@Bean
public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
KeycloakAuthenticationProcessingFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
@Bean
public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(KeycloakPreAuthActionsFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and()
.addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class)
.addFilterBefore(keycloakAuthenticationProcessingFilter(), X509AuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and().authorizeRequests()
.antMatchers("/**").authenticated().anyRequest().permitAll();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment