Gestionnaire d'authentification personnalisé avec Sécurité Spring et configuration Java


J'utilise Spring Security avec SpringMVC pour créer une application Web (je vais me référer à cela comme la WebApp pour plus de clarté) qui parle à une application existante (je vais me référer à cela comme BackendApp).

Je souhaite déléguer les responsabilités d'authentification à l'application principale (afin de ne pas avoir besoin de synchroniser les deux applications).

Pour implémenter cela, je voudrais que la WebApp (exécutant spring security) communique avec l'application principale via REST avec le nom d'utilisateur et le mot de passe fourni par l'utilisateur sous forme et authentifié selon que la réponse de l'application principale est 200 OK ou 401 Non autorisé.

Je comprends que je devrai écrire un gestionnaire d'authentification personnalisé pour ce faire, mais je suis très nouveau sur spring et je ne trouve aucune information sur la façon de l'implémenter.

Je crois que je vais devoir faire quelque chose comme ceci:

public class CustomAuthenticationManager implements AuthenticationManager{

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String username = authentication.getName();
        String pw       = authentication.getCredentials().toString();

        // Code to make rest call here and check for OK or Unauthorised.
        // What do I return?

    }

}

Dois-je définir l'authentification.setAuthenticated (true) si réussi et false si autrement et c'est tout?

Une fois que c'est écrit, comment configurer spring Security pour utiliser ce gestionnaire d'authentification à l'aide d'un fichier de configuration java?

Merci d'avance pour toute aide.

Author: Jeff I, 2015-08-05

4 answers

Jetez un oeil à mon échantillon ci-dessous. Vous devez renvoyer un UsernamePasswordAuthenticationToken. Il contient le principal et les autorisations octroyées. J'espère que je pourrais aider:)

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String username = authentication.getPrincipal() + "";
    String password = authentication.getCredentials() + "";

    User user = userRepo.findOne(username);
    if (user == null) {
        throw new BadCredentialsException("1000");
    }
    if (user.isDisabled()) {
        throw new DisabledException("1001");
    }
    if (!encoder.matches(password, user.getPassword())) {
        throw new BadCredentialsException("1000");
    }
    List<Right> userRights = rightRepo.getUserRights(username);
    return new UsernamePasswordAuthenticationToken(username, password, userRights.stream().map(x -> new SimpleGrantedAuthority(x.getName())).collect(Collectors.toList()));
}

PS: userRepo et rightRepo sont des référentiels Spring-Data-JPA qui accèdent à mon User-DB personnalisé

SpringSecurity JavaConfig:

@Configuration
@EnableWebMvcSecurity
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {

public MySecurityConfiguration() {
    super(false);
}

@Override
protected AuthenticationManager authenticationManager() throws Exception {
    return new ProviderManager(Arrays.asList((AuthenticationProvider) new AuthProvider()));
}

}
 26
Author: Halko Karr-Sajtarevic, 2015-08-05 10:57:27

Dans son plus simple:

@Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {
        String username = auth.getName();
        String password = auth.getCredentials().toString();
        // to add more logic
        List<GrantedAuthority> grantedAuths = new ArrayList<>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        return new UsernamePasswordAuthenticationToken(username, password, grantedAuths);
    }
 5
Author: mel3kings, 2016-05-20 02:29:44

Vous devez d'abord configurer Spring Security pour utiliser votre AuthenticationProvider personnalisé. Donc, dans votre printemps-sécurité.xml (ou fichier de configuration équivalent) vous devez définir la classe qui implémente cette fonctionnalité. Par exemple:

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>

<!-- Bean implementing AuthenticationProvider of Spring Security -->
<beans:bean id="myAuthenticationProvider" class="com.teimas.MyAutenticationProvider">
</beans:bean>

Deuxièmement, vous devez implémenter AuthenticationProvider comme dans votre exemple. Spécialement la méthode authenticate (Authentication authentication) dans laquelle votre appel rest doit être. Par exemple:

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    User user = null;
    try {
        //use a rest service to find the user. 
        //Spring security provides user login name in authentication.getPrincipal()
            user = userRestService.loadUserByUsername(authentication.getPrincipal().toString());
    } catch (Exception e) {
        log.error("Error loading user, not found: " + e.getMessage(), e);
    }

    if (user == null) {
        throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal()));
    } else if (!user.isEnabled()) {
        throw new UsernameNotFoundException(String.format("Not found enabled user for username ", user.getUsername()));
    }
    //check user password stored in authentication.getCredentials() against stored password hash
    if (StringUtils.isBlank(authentication.getCredentials().toString())
        || !passwordEncoder.isPasswordValid(user.getPasswordHash(), authentication.getCredentials().toString()) {
        throw new BadCredentialsException("Invalid credentials");
    }

    //doLogin makes whatever is necesary when login is made (put info in session, load other data etc..)
    return doLogin(user);
} 
 3
Author: Ricardo Vila, 2016-04-19 15:26:53

Ma solution est presque la même que la première réponse:

1) Vous avez besoin d'une classe qui implémente le Fournisseur d'Authentification

@Service
@Configurable
public class CustomAuthenticationProvider implements AuthenticationProvider    {
      @Override
      public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    // Your code of custom Authentication
}
}

2) En face de la première réponse, vous n'avez pas besoin d'avoir le code suivant dans votre WebSecurityConfiguration si vous n'avez que ce fournisseur personnalisé.

@Override
protected AuthenticationManager authenticationManager() throws Exception {
     return new ProviderManager(Arrays.asList((AuthenticationProvider) new  AuthProvider()));
}

Le problème est que Spring recherche les fournisseurs disponibles et utilise la valeur par défaut si rien d'autre n'est trouvé. Mais comme vous avez l'implémentation de l'AuthenticationProvider-votre la mise en œuvre sera utilisée.

 0
Author: Andrew Gans, 2016-11-17 06:13:28