I am trying to authenticate the user before he accesses the swagger-ui. I am using Keycloak for ID management. I am following the example given here.
Below is my security config
@Configuration
@EnableWebSecurity
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = new KeycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
authenticationManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(
(request, response, accessDeniedException) -> response.setStatus(HttpServletResponse.SC_NOT_FOUND)
)
.and()
.anonymous()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic().disable()
.formLogin().disable()
.logout().disable();
}
}
Below is my swagger config
@Configuration
@Slf4j
public class SwaggerConfig {
@Value("${keycloak.auth-server-url}")
private String AUTH_SERVER;
@Value("${keycloak.credentials.secret}")
private String CLIENT_SECRET;
@Value("${keycloak.resource}")
private String CLIENT_ID;
@Value("${keycloak.realm}")
private String REALM;
private static final String OAUTH_NAME = "spring_oauth";
private static final String ALLOWED_PATHS = "src/main/java/io/chait/swagger/demo/.*";
private static final String GROUP_NAME = "swagger-demo";
private static final String TITLE = "API Documentation for swagger-demo Application";
private static final String DESCRIPTION = "Description here";
private static final String VERSION = "1.0";
@Bean
public Docket taskApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName(GROUP_NAME)
.useDefaultResponseMessages(true)
.apiInfo(apiInfo())
.select()
.paths(regex(ALLOWED_PATHS))
.build()
.securitySchemes(Arrays.asList(securityScheme()))
.securityContexts(Arrays.asList(securityContext()));
}
private ApiInfo apiInfo() {
return new
ApiInfoBuilder().title(TITLE).description(DESCRIPTION).version(VERSION).build();
}
@Bean
public SecurityConfiguration security() {
return SecurityConfigurationBuilder.builder()
.realm(REALM)
.clientId(CLIENT_ID)
.clientSecret(CLIENT_SECRET)
.appName(GROUP_NAME)
.scopeSeparator(" ")
.build();
}
private SecurityScheme securityScheme() {
GrantType grantType =
new AuthorizationCodeGrantBuilder()
.tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/token", GROUP_NAME))
.tokenRequestEndpoint(
new TokenRequestEndpoint(AUTH_SERVER + "/realms/" + REALM + "/protocol/openid-connect/auth", CLIENT_ID, CLIENT_SECRET))
.build();
SecurityScheme oauth =
new OAuthBuilder()
.name(OAUTH_NAME)
.grantTypes(Arrays.asList(grantType))
.scopes(Arrays.asList(scopes()))
.build();
return oauth;
}
private AuthorizationScope[] scopes() {
AuthorizationScope[] scopes = {
new AuthorizationScope("user", "for CRUD operations"),
new AuthorizationScope("read", "for read operations"),
new AuthorizationScope("write", "for write operations")
};
return scopes;
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(Arrays.asList(new SecurityReference(OAUTH_NAME, scopes())))
.forPaths(PathSelectors.regex(ALLOWED_PATHS))
.build();
}
}
Below is my properties file
spring.datasource.url=jdbc:postgresql://localhost:5432/personal
spring.datasource.password=postgres
spring.datasource.username=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
# keycloak config
keycloak.auth-server-url=http://localhost:8180/auth
keycloak.realm=local
keycloak.resource=swagger-demo
keycloak.public-client=true
keycloak.credentials.secret=fb652c4a-70cb-4b81-a339-fa87054f77a0
spring.application.name=swagger-demo
Below is my boot class
@SpringBootApplication
@EnableJpaRepositories
@EnableSwagger2
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
When I fire up the application and access http://localhost:8080/swagger-demo/swagger-ui/
the app redirects me to Keycloak where I enter user credentials. Upon authenticating, I get the exception below
2021-04-02 21:46:04.163 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator : failed to turn code into token
2021-04-02 21:46:04.164 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator : status from server: 401
2021-04-02 21:46:04.164 ERROR 4208 --- [nio-8080-exec-8] o.k.adapters.OAuthRequestAuthenticator : {"error":"unauthorized_client","error_description":"Client secret not provided in request"}
All the related threads regarding this exception are pointing towards a change in nginx config or Docker config. I am not using either of them and I am running this entirely on local. I am not sure what I am missing here. I have the code here. Any help is appreciated.