webentwicklung-frage-antwort-db.com.de

Migration zu Spring Boot 2 - Sicherheitscodiertes Kennwort sieht nicht aus wie BCrypt

Ich hatte einen Spring Boot 1.5.9-Autorisierungsserver, der BCrypt zur Kennwortspeicherung verwendet. Ich versuche, auf 2.0 zu migrieren. Ich kann jedoch kein Token mehr für die Autorisierung abrufen.

Die Antwort vom Server lautet:

    "timestamp": "2018-03-09T15:22:06.576+0000",
    "status": 401,
    "error": "Unauthorized",
    "message": "Unauthorized",
    "path": "/oauth/token"
}

mit der Konsole wird Folgendes ausgegeben: 2018-03-09 09:22:06.553 WARN 20976 --- [nio-8090-exec-1] o.s.s.c.bcrypt.BCryptPasswordEncoder : Encoded password does not look like BCrypt.

Dieser Teil der Anwendung hat vorher gut funktioniert. Die einzigen Änderungen, die ich vorgenommen habe, waren die build.gradle-Datei (springBootVersion wird geändert, das io.spring.dependency-management-Plugin hinzugefügt und runtime('org.springframework.boot:spring-boot-devtools') hinzugefügt.).

buildscript {
    ext {
        springBootVersion = '2.0.0.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'Java'
apply plugin: 'Eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.midamcorp'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
    mavenCentral()
}



dependencies {
    compile('org.springframework.boot:spring-boot-starter-data-rest')
    compile('org.springframework.boot:spring-boot-starter-jdbc')
        compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('org.springframework.boot:spring-boot-starter-security')
    compile('commons-io:commons-io:2.5')    
    compile('org.springframework.security:spring-security-jwt:1.0.7.RELEASE')
    compile('org.springframework.security.oauth:spring-security-oauth2:2.2.1.RELEASE')
    compile 'com.Microsoft.sqlserver:mssql-jdbc:6.2.2.jre8'   
    runtime('org.springframework.boot:spring-boot-devtools')

    testCompile('org.springframework.boot:spring-boot-starter-test')
    testCompile('org.springframework.security:spring-security-test')
testCompile('com.h2database:h2:1.4.196')

}

Die Logik zum Hashing der Passwörter befindet sich in zwei separaten Konfigurationsdateien:

package com.midamcorp.auth_server.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.midamcorp.auth_server.service.OAuthUserDetailsService;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private OAuthUserDetailsService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
}

    // Hash password
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService)
        .passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
               .sessionManagement()
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
               .and()
               .httpBasic()
               .realmName("test")
               .and()
               .csrf()
               .disable();

    }
}

und 

package com.midamcorp.auth_server.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;


// Contains properties common to both authorization and resource servers
@Configuration
public class AppConfig {


        @Value("${spring.datasource.url}")
        private String datasourceUrl;

        @Value("${spring.datasource.driverClassName}")
        private String dbDriverClassName;

        @Value("${spring.datasource.username}")
        private String dbUsername;

        @Value("${spring.datasource.password}")
        private String dbPassword;

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

        @Bean
        public DataSource dataSource() {
            final DriverManagerDataSource dataSource = new DriverManagerDataSource();

            dataSource.setDriverClassName(dbDriverClassName);
            dataSource.setUrl(datasourceUrl);
            dataSource.setUsername(dbUsername);
            dataSource.setPassword(dbPassword);

            return dataSource;
        }    

        // Refrence: http://www.baeldung.com/spring-security-oauth-jwt

        /* !!!!!!!!!!!!!!!!!!!!!!!!!! 
        ** TODO 
        * Secure key file for deployment.
        !!!!!!!!!!!!!!!!!!!! */
           @Bean
           public JwtAccessTokenConverter accessTokenConverter() {
              JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
              KeyStoreKeyFactory keyStoreKeyFactory = 
                      new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"), "mypass".toCharArray());
                    converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
              return converter;
           }


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


}

OAuthUser-Klasse:

    package com.midamcorp.auth_server.model;


import Java.util.List;

import javax.persistence.*;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;

import com.fasterxml.jackson.annotation.JsonIgnore;


@Entity
@Table(name="auth_user")
public class OAuthUser {

//    @Autowired 
//    @Transient
//    private PasswordEncoder passwordEncoder;
//    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name= "username")
    private String userName;

    @Column(name="password")
    @JsonIgnore
    private String password;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(name="email")
    private String email;

    @Column(name="is_enabled")
    private boolean isEnabled;

     /**
      * Reference: https://github.com/nydiarra/springboot-jwt/blob/master/src/main/Java/com/nouhoun/springboot/jwt/integration/domain/User.Java
     * Roles are being eagerly loaded here because
     * they are a fairly small collection of items for this example.
     */
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "user_role", joinColumns
            = @JoinColumn(name = "user_id",
            referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "role_id",
                    referencedColumnName = "id"))
private List<Role> roles;


    public OAuthUser() {};
    public OAuthUser(String firstName, String lastName, String user, String pass) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.userName = user;
        this.password = pass;
    }
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public boolean isEnabled() {
        return isEnabled;
    }

    public void setEnabled(boolean isEnabled) {
        this.isEnabled = isEnabled;
    }
}

Ich habe gehört, dass an Spring Security wesentliche Änderungen vorgenommen wurden, aber ich bin nicht sicher, ob ich das Problem lösen möchte. Jede Anleitung wäre dankbar.

Vielen Dank.

BEARBEITEN

Nur ein paar weitere Details, falls sie helfen. Auch wenn ich während der Ausführung von Spring Boot 2.0 einen neuen Benutzer hinzufüge:

OAuthUser user = new OAuthUser();   

            user.setFirstName("K");
            user.setLastName("M");
            user.setPassword(passwordEncoder.encode("L"));
            user.setUserName("KLM");

repository.save(user);

wenn Sie den neuen Benutzernamen und das neue Passwort eingeben, erhalte ich immer noch den Fehler.

ZWEI BEARBEITEN:

Fordern Sie die Ergebnisse fälschlicherweise an:

curl --request POST \
  --url http://web:[email protected]:8090/oauth/token \
  --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \
  --form grant_type=password \
  --form username=KLM \
  --form password=L

Autorisierungsserver-Konfiguration:

    package com.midamcorp.auth_server.config;

import Java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.AccessTokenConverter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

// Reference: https://dazito.com/Java/spring-boot-and-oauth2-with-jdbc

@EnableAuthorizationServer
@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter{
    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private AccessTokenConverter converter;

     private final AppConfig appConfig; 

    private AuthenticationManager authenticationManager;

    @Autowired
    public AuthServerConfig(AuthenticationManager authenticationManager, AppConfig appConfig) {
        this.authenticationManager = authenticationManager;
        this.appConfig = appConfig;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()");
        security.tokenKeyAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {

    JdbcClientDetailsService details = new JdbcClientDetailsService(appConfig.dataSource());

        configurer.jdbc(appConfig.dataSource());
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        endpoints.tokenStore(tokenStore)
                .accessTokenConverter(converter)
            .authenticationManager(authenticationManager);
    }



       @Bean
       @Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
       public DefaultTokenServices tokenServices() {
          DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
          defaultTokenServices.setTokenStore(tokenStore);
          defaultTokenServices.setSupportRefreshToken(true);
          return defaultTokenServices;
       }       



}

Ich verwende folgende Eigenschaften:

 spring.datasource.url=jdbc:sqlserver://localhost;databaseName=API
spring.datasource.username=**
spring.datasource.password=**
spring.datasource.driverClassName=com.Microsoft.sqlserver.jdbc.SQLServerDriver
server.port=8090
9
KellyMarchewa

Ich habe es gelöst, das ClientSecret-Passwort zu kodieren

@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
    configurer
            .inMemory()
            .withClient(clientId)
            .secret(encode(clientSecret))
            .authorizedGrantTypes(grantType)
            .scopes(scopeRead, scopeWrite)
            .resourceIds(resourceIds);
}
2
Andres

Als die Abhängigkeit von oauth2 in die Cloud verschoben wurde, begann ich mit diesem Problem zu konfrontieren. Früher war es Teil des Sicherheitsrahmens:

<dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId></dependency>

Jetzt ist es Teil des Cloud-Frameworks:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>

Wenn Sie also die Cloud-Abhängigkeit (Finchley.RELEASE) verwenden, müssen Sie das Geheimnis wie folgt kodieren:

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
         clients
                .inMemory()
                .withClient("clientapp")
                .authorizedGrantTypes("password","refresh_token")
                .authorities("USER")
                .scopes("read", "write")
                .resourceIds(RESOURCE_ID)
                .secret(passwordEncoder.encode("SECRET"));
    }

Hoffe, das wird dir helfen.

1
PKumar