wake-up-neo.com

Spring Security 5: Es ist kein PasswordEncoder für die ID "null" zugeordnet

Ich migriere von Spring Boot 1.4.9 zu Spring Boot 2.0 und auch zu Spring Security 5 und versuche, mich über OAuth 2 zu authentifizieren. Es wird jedoch folgender Fehler angezeigt:

Java.lang.IllegalArgumentException: Für die ID "null" ist kein PasswordEncoder zugeordnet

Aus der Dokumentation von Spring Security 5 erfahre ich, dass das Speicherformat für das Passwort geändert wurde.

In meinem aktuellen Code habe ich mein Passwort Encoder Bean erstellt als:

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Es gab mir jedoch folgenden Fehler:

Das verschlüsselte Passwort sieht nicht aus wie BCrypt

Also aktualisiere ich den Encoder gemäß dem Spring Security 5 Dokument zu:

@Bean
public PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

Nun, wenn ich das Passwort in der Datenbank sehen kann, wird es gespeichert als

{bcrypt}$2a$10$LoV/3z36G86x6Gn101aekuz3q9d7yfBp3jFn7dzNN/AL5630FyUQ

Wenn der erste Fehler behoben ist und ich versuche, die Authentifizierung durchzuführen, wird der folgende Fehler angezeigt:

Java.lang.IllegalArgumentException: Für die ID "null" ist kein PasswordEncoder zugeordnet

Um dieses Problem zu lösen, habe ich alle folgenden Fragen von Stackoverflow ausprobiert:

Hier ist eine Frage, die meiner ähnlich ist, aber nicht beantwortet wird:

HINWEIS: Ich speichere bereits ein verschlüsseltes Passwort in der Datenbank, sodass ich es nicht erneut in UserDetailsService verschlüsseln muss.

In der Dokumentation Spring security 5 wurde vorgeschlagen, dass Sie diese Ausnahme wie folgt behandeln können:

DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches (PasswordEncoder)

Wenn dies die Lösung ist, wo soll ich sie dann hinstellen? Ich habe versucht, es wie folgt in PasswordEncoder Bean zu schreiben, aber es hat nicht funktioniert:

DelegatingPasswordEncoder def = new DelegatingPasswordEncoder(idForEncode, encoders);
def.setDefaultPasswordEncoderForMatches(passwordEncoder);

MyWebSecurity-Klasse

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {

        web
                .ignoring()
                .antMatchers(HttpMethod.OPTIONS)
                .antMatchers("/api/user/add");
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

MyOauth2-Konfiguration

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;


    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

    @Bean
    public DefaultAccessTokenConverter accessTokenConverter() {
        return new DefaultAccessTokenConverter();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        endpoints
                .tokenStore(tokenStore())
                .tokenEnhancer(tokenEnhancer())
                .accessTokenConverter(accessTokenConverter())
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                .inMemory()
                .withClient("test")
                .scopes("read", "write")
                .authorities(Roles.ADMIN.name(), Roles.USER.name())
                .authorizedGrantTypes("password", "refresh_token")
                .secret("secret")
                .accessTokenValiditySeconds(1800);
    }
}

Bitte führen Sie mich mit diesem Problem. Ich habe Stunden damit verbracht, dieses Problem zu beheben, kann es aber nicht beheben.

32
Jimmy

Wenn Sie ClientDetailsServiceConfigurer konfigurieren, müssen Sie auch das neue Kennwortspeicherformat auf das Clientgeheimnis anwenden.

.secret("{noop}secret")
53

Für alle, die mit demselben Problem konfrontiert sind und keine sichere Lösung benötigen - hauptsächlich zum Testen und Debuggen - können Benutzer im Arbeitsspeicher weiterhin konfiguriert werden.

Dies ist nur zum Herumspielen gedacht - kein reales Szenario.

Der unten verwendete Ansatz ist veraltet.

Hier habe ich es bekommen:


Fügen Sie in Ihrem WebSecurityConfigurerAdapter Folgendes hinzu:

@SuppressWarnings("deprecation")
@Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}

Hier werden offensichtlich Passwörter gehasht, sind aber immer noch im Speicher verfügbar.


Natürlich können Sie auch ein echtes PasswordEncoder wie BCryptPasswordEncoder verwenden und dem Passwort die richtige ID voranstellen:

// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
7
rocksteady

.password("{noop}password") zur Sicherheitskonfigurationsdatei hinzufügen.

Beispielsweise :

auth.inMemoryAuthentication()
        .withUser("admin").roles("ADMIN").password("{noop}password");
4

Immer wenn Spring das Passwort speichert, fügt es den verschlüsselten Passwörtern wie bcrypt, scrypt, pbkdf2 usw. ein Präfix von encoder hinzu, sodass es zum Decodieren des Passworts einen geeigneten Encoder verwenden kann. Wenn das verschlüsselte Kennwort kein Präfix enthält, wird defaultPasswordEncoderForMatches verwendet. Sie können die Übereinstimmungsmethode von DelegatingPasswordEncoder.class anzeigen, um zu sehen, wie sie funktioniert. Daher müssen wir defaultPasswordEncoderForMatches in den folgenden Zeilen festlegen.

@Bean(name="myPasswordEncoder")
public PasswordEncoder getPasswordEncoder() {
        DelegatingPasswordEncoder delPasswordEncoder=  (DelegatingPasswordEncoder)PasswordEncoderFactories.createDelegatingPasswordEncoder();
        BCryptPasswordEncoder bcryptPasswordEncoder =new BCryptPasswordEncoder();
    delPasswordEncoder.setDefaultPasswordEncoderForMatches(bcryptPasswordEncoder);
    return delPasswordEncoder;      
}

Jetzt müssen Sie diesen Encoder möglicherweise auch Ihrem Authentifizierungsanbieter mit DefaultPasswordEncoderForMatches zur Verfügung stellen. Ich habe das mit den folgenden Zeilen in meinen Konfigurationsklassen gemacht.

@Bean
    @Autowired  
    public DaoAuthenticationProvider getDaoAuthenticationProvider(@Qualifier("myPasswordEncoder") PasswordEncoder passwordEncoder, UserDetailsService userDetailsServiceJDBC) {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        daoAuthenticationProvider.setUserDetailsService(userDetailsServiceJDBC);
        return daoAuthenticationProvider;
    }
1
Vikky

Hinsichtlich

Das verschlüsselte Passwort sieht nicht wie BCrypt aus

In meinem Fall gab es eine Inkongruenz in der BCryptPasswordEncoder-Stärke, die vom Standardkonstruktor (10) verwendet wurde, da pwd-Hash mit Stärke 4 generiert wurde. Ich habe die Stärke also explizit festgelegt.

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(4);
}

auch meine Spring Security Version ist 5.1.6 und funktioniert perfekt mit BCryptPasswordEncoder

0
Bender