J'essaie de faire une chose simple.
Je veux faire une demande à un seul point de terminaison et envoyer un jeton au porteur (à partir d'un client), je veux que ce jeton soit validé et en fonction du rôle attribué sur la demande d'acceptation/refus de keycloak sur mon point de terminaison.
J'ai suivi de nombreux tutoriels et même des livres, mais surtout je ne comprends tout simplement pas.
Suivi de cela pour configurer mes informations de capuchon (domaine, rôle, utilisateur) https://medium.com/@bcarunmail/securing-rest-api-using-keycloak-and-spring-oauth2-6ddf3a1efcc2
Alors,
J'ai essentiellement mis en place mon keycloak avec un client, un utilisateur avec un rôle spécifique "utilisateur" et l'ai configuré comme ceci:
@Configuration
@KeycloakConfiguration
//@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConf extends KeycloakWebSecurityConfigurerAdapter
{
/**
* Registers the KeycloakAuthenticationProvider with the authentication manager.
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
/**
* Defines the session authentication strategy.
*/
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
@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
{
super.configure(http);
http
.authorizeRequests()
.antMatchers("/user/*").hasRole("admin")
.antMatchers("/admin*").hasRole("user")
}
}
Je ne comprends pas pourquoi dans de nombreux tutoriels je vois cela (comme la dernière règle):
.anyRequest().permitAll();
Fondamentalement, lorsque je définis que je n'ai aucune sécurité, je peux appeler les points de terminaison sans jeton de support.
Mais quand j'ajoute cela comme dernière règle
.anyRequest().denyAll();
J'ai toujours un 403.
Débogage J'ai trouvé ceci:
La demande consiste à traiter l'authentification
f.KeycloakAuthenticationProcessingFilter : Attempting Keycloak authentication
o.k.a.BearerTokenRequestAuthenticator : Found [1] values in authorization header, selecting the first value for Bearer.
o.k.a.BearerTokenRequestAuthenticator : Verifying access_token
o.k.a.BearerTokenRequestAuthenticator : successful authorized
a.s.a.SpringSecurityRequestAuthenticator : Completing bearer authentication. Bearer roles: []
o.k.adapters.RequestAuthenticator : User 'testuser' invoking 'http://localhost:9090/api/user/123' on client 'users'
o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
f.KeycloakAuthenticationProcessingFilter : Auth outcome: AUTHENTICATED
o.s.s.authentication.ProviderManager : Authentication attempt using org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider
o.s.s.core.session.SessionRegistryImpl : Registering session 5B871A0E2AF55B70DC8E3B7436D79333, for principal testuser
f.KeycloakAuthenticationProcessingFilter : Authentication success using bearer token/basic authentication. Updating SecurityContextHolder to contain: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@355f68d6: Principal: testuser; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@5d7a32a9; Not granted any authorities
[nio-9090-exec-3] o.s.security.web.FilterChainProxy : /api/user/123 at position 8 of 15 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
nio-9090-exec-3] o.s.s.w.s.DefaultSavedRequest : pathInfo: both null (property equals)
[nio-9090-exec-3] o.s.s.w.s.DefaultSavedRequest : queryString: both null (property equals)
On dirait que je n'obtiens aucun rôle de porteur ...
Mes dépendances:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>6.0.1</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-security-adapter</artifactId>
<version>6.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Mon problème?
Je demande l'envoi d'un jeton d'accès:
client_id -> my client from keycloak
username -> my user from keycloak
password -> my password from keycloak
grant_type -> password
client_secret -> from keycloak
J'obtiens un jeton, puis j'utilise pour demander à mon endpoint d'application. Mes demandes sont toujours valides quel que soit le point de terminaison que j'utilise (celui avec l'utilisateur de rôle ou avec l'administrateur de rôle).
Dans mes propriétés, j'ai quelque chose comme ça:
keycloak:
auth-server-url: http://localhost:8080/auth/
resource: users-api
credentials:
secret : my-secret
use-resource-role-mappings : true
realm: my-realm
realmKey: my-key
public-client: true
principal-attribute: preferred_username
bearer-only: true
Une idée de comment activer réellement les rôles dans ce cas?
Dois-je configurer un client pour utiliser JWT? des idées?
J'ai également ajouté les annotations sur mon point de terminaison
@Secured("admin")
@PreAuthorize("hasAnyAuthority('admin')")
mais ils ne font rien ...
-- ÉDITER --
Après avoir corrigé l'URL pour correspondre à la ressource, j'obtiens toujours 403.
"realm_access": {
"roles": [
"offline_access",
"admin",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
Est-il en quelque sorte lié le resource_access à mon problème?
Essayez-vous sans le @Configuration
? Je pense que vous avez seulement besoin de @KeycloakConfiguration
annotation sur votre classe SecurityConf
.
Vos antMatchers respectent-ils la casse?
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/user/**").hasRole("user")
.antMatchers("/api/admin/**").hasRole("admin")
.anyRequest().authenticated();
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
// SimpleAuthorityMapper is used to remove the ROLE_* conventions defined by Java so
// we can use only admin or user instead of ROLE_ADMIN and ROLE_USER
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@PreAuthorize("hasRole('admin')")