OAuth authentification with spring backend and keycloak

734 views
Skip to first unread message

djehle...@gmail.com

unread,
Nov 6, 2018, 8:15:21 AM11/6/18
to Swagger
Hello, 

I have a secured spring backend and an angular frontend. The backend has a swagger-ui which is accessible without authentification. I would like to be able to call a backend controller with this swagger-ui, therefore I need an authentification config in swagger/spring.

I have created two clients in keycloak, one with access type 'public' for frontend authentification, one with access type 'bearer-only' for the backend application. The interface between angular and spring was designed with swagger. The Swagger UI is still visible thanks to
HttpSecurity.authorizeRequests().antMatchers(new String[]{"/swagger-ui.html", "/swagger/swagger.yaml", "/swagger-resources", "/swagger-resources/**", "/webjars/springfox-swagger-ui/**"}).permitAll()

I would like to get an access token for calls in Swagger UI. Adding the java code and swagger yaml configuration from this posting Keycloak integration in Swagger does not work so far. I created a third client in keycloak for the swagger-ui with a 'public' access type.

My swagger.yaml:

... securityDefinitions: OAuth2: type: oauth2 flow: implicit authorizationUrl: http://localhost:8080/auth/ scopes: openid: openid profile: profile security: - OAuth2: [openid, profile]


This is my swagger config class
(note: Swagger builds the ui from the provided yaml file and NOT from the controller classes)

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

private static final Logger LOGGER = LoggerFactory.getLogger(SwaggerConfiguration.class);

@Bean
WebMvcConfigurer configurer() {
 
return new WebMvcConfigurer() {
 
@Override
 
public void addResourceHandlers(ResourceHandlerRegistry registry) {
 registry
 
.addResourceHandler("/swagger/**")
 
.addResourceLocations("classpath:swagger/");

 
}
 
};
}

@Primary
@Bean
public SwaggerResourcesProvider swaggerResourcesProvider() {
 
return () -> {
 
SwaggerResource resource = new SwaggerResource();
 resource
.setName("QM-API");
 resource
.setLocation("/swagger/swagger.yaml");

 
SwaggerResource models = new SwaggerResource();
 models
.setName("QM-Models");
 models
.setLocation("/swagger/qm-common-definitions.yaml");

 
List<SwaggerResource> resources = new ArrayList<>();
 resources
.add(resource);
 resources
.add(models);
 
return resources;
 
};
}

@Bean
public SecurityConfiguration securityConfiguration() {

 
Map<String, Object> additionalQueryStringParams=new HashMap<>();
 additionalQueryStringParams
.put("nonce","123456");

 
return SecurityConfigurationBuilder.builder()
 
.clientId("test-uid").realm("Master").appName("swagger-ui")
 
.additionalQueryStringParams(additionalQueryStringParams)
 
.build();
}

private List<SecurityContext> buildSecurityContext() {
 
List<SecurityReference> securityReferences = new ArrayList<>();

 securityReferences
.add(SecurityReference.builder().reference("oauth2").scopes(scopes().toArray(new AuthorizationScope[]{})).build());

 
SecurityContext context = SecurityContext.builder().forPaths(Predicates.alwaysTrue()).securityReferences(securityReferences).build();

 
List<SecurityContext> ret = new ArrayList<>();
 ret
.add(context);
 
return ret;
}

private List<? extends SecurityScheme> buildSecurityScheme() {
 
List<SecurityScheme> lst = new ArrayList<>();
 lst
.add(new ApiKey("api_key", "X-API-KEY", "header"));

 
LoginEndpoint login = new LoginEndpointBuilder().url("http://localhost:8080/auth/realms/master/protocol/openid-connect/auth").build();

 
List<GrantType> gTypes = new ArrayList<>();
 gTypes
.add(new ImplicitGrant(login, "acces_token"));

 lst
.add(new OAuth("oauth2", scopes(), gTypes));
 
return lst;
}

private List<AuthorizationScope> scopes() {
 
List<AuthorizationScope> scopes = new ArrayList<>();
 
for (String scopeItem : new String[]{"openid=openid", "profile=profile"}) {
 
String scope[] = scopeItem.split("=");
 
if (scope.length == 2) {
 scopes
.add(new AuthorizationScopeBuilder().scope(scope[0]).description(scope[1]).build());
 
} else {
 LOGGER
.warn("Scope '{}' is not valid (format is scope=description)", scopeItem);
 
}
 
}

 
return scopes;
}
}

With this configuration I have an 'Authorize' button in my swagger-ui. Pressing this button opens a modal form, giving me the opportunity to enter a client_id, and displays checkboxes for the scopes. Pressing the 'Authorize' button in this form
opens a new tab in my browser, showing the keycloak welcome page. Keycloak does not show any log error message.


I experimented a bit with the 'flow' in the swagger.yaml. Changing it to 'password' caused the modal form to give more input like 'user' and 'password' and causing the keycloak to log warn messages, but did not get me further.


What can I do to authenticate the swagger ui against keycloak in order to get access to the backend?

Reply all
Reply to author
Forward
0 new messages