roguequery
roguequery

Reputation: 974

Spring Boot 2.0.0 + OAuth2

Does Spring Boot 2 + Sping Security OAuth2 still support the @AuthorizationServer annotation? From reading the release notes some things haven't been ported over:

Oauth2 Support

Here is the relevant section of my build.grade:

Auth Server

// security
compile "org.springframework.boot:spring-boot-starter-security:${springBootVersion}"
// oauth
// https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2
compile "org.springframework.security.oauth:spring-security-oauth2:2.2.1.RELEASE"

Client Server

// support for Oauth2 user token services not yet migrated into Spring Boot 2.0
compile "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.1.BUILD-SNAPSHOT"

And right now my Authorization Server Oauth2 endpoints just return a 401 when i try to pass a client-id and client-secret in as Basic Authentication to /oauth/token. Passing in a username and password gives a different code path. So it looks like the OAuth filters aren't quite lined up.

I also found this as well: Spring Boot 2 OAuth2 starter changes.

Has there been a configuration update or do I need a different set of gradle dependencies to restore the Authorization Server to it's previous state?

Thanks!


UPDATE

I wanted to close the loop on this question. In addition to encrypting the client-secrets. The RedisTokenStore issue has also been resolved as of Spring OAuth 2.3.2: Spring OAuth 2.3.2

Upvotes: 7

Views: 9416

Answers (4)

dur
dur

Reputation: 16969

Spring Security 5 uses a modernized password storage, see OAuth2 Autoconfig:

If you use your own authorization server configuration to configure the list of valid clients through an instance of ClientDetailsServiceConfigurer as shown below, take note that the passwords you configure here are subject to the modernized password storage that came with Spring Security 5.

To solve your problem, see Spring Security Reference:

Troubleshooting

The following error occurs when one of the passwords that are stored has no id as described in the section called “Password Storage Format”.

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)

The easiest way to resolve the error is to switch to explicitly provide the PasswordEncoder that you passwords are encoded with. The easiest way to resolve it is to figure out how your passwords are currently being stored and explicitly provide the correct PasswordEncoder. If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a NoOpPasswordEncoder bean. For example, if you are using Java Configuration, you can create a configuration that looks like:

Reverting to NoOpPasswordEncoder is not considered to be secure. You should instead migrate to using DelegatingPasswordEncoder to support secure password encoding.

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

if you are using XML configuration, you can expose a PasswordEncoder with the id passwordEncoder:

<b:bean id="passwordEncoder"
   class="org.springframework.security.crypto.NoOpPasswordEncoder" factory-method="getInstance"/>

Alternatively, you can prefix all of your passwords with the correct id and continue to use DelegatingPasswordEncoder. For example, if you are using BCrypt, you would migrate your password from something like:

$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

to

{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

Upvotes: 8

gultekinfatih
gultekinfatih

Reputation: 143

OAuth2 AuthorizationServer uses basic authentication.

So, you also need to encode your client secret with delegatedPasswordEncoder in AuthorizationServerConfig to completely solve "There is no PasswordEncoder mapped for the id "null" " exception.

Yao Liu's answer solved my problem.

1) created a bean to auto wire PasswordEncoder;

@Bean
public PasswordEncoder passwordEncoder() {
    String idForEncode = "bcrypt";
    Map<String, PasswordEncoder> encoderMap = new HashMap<>();
    encoderMap.put(idForEncode, new BCryptPasswordEncoder());
    return new DelegatingPasswordEncoder(idForEncode, encoderMap);
}

2) Auto wired passwordEncoder in AuthorizationServerConfig class;

@Autowired
private PasswordEncoder passwordEncoder;

3) encoded CLIENT_SECRET with passwordEncoder.

@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
    configurer
         .inMemory()
         .withClient(CLIENT_ID)
         .secret(passwordEncoder.encode(CLIENT_SECRET))
         .authorizedGrantTypes(GRANT_TYPE_FOR_LOGIN, GRANT_TYPE_FOR_REFRESH)
         .scopes(SCOPE_READ, SCOPE_WRITE)
         .accessTokenValiditySeconds(TOKEN_VALIDITY_SECONDS)
         .refreshTokenValiditySeconds(TOKEN_VALIDITY_SECONDS)
         .resourceIds(RESOURCES_IDS);
}

That's it.

Upvotes: 7

roguequery
roguequery

Reputation: 974

I wanted to close the loop on this question. In addition to encrypting the client-secrets. The RedisTokenStore issue has also been resolved as of Spring OAuth 2.3.2: Spring OAuth 2.3.2

Upvotes: 0

Yao Liu
Yao Liu

Reputation: 426

As @false_memories stated above, with Spring Boot 2 you need to encode your secret. In my project, it looks like:

public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    String secretEncoded = passwordEncoder().encode("secret");
    clients.inMemory().withClient("some-web-app").secret(secretEncoded).accessTokenValiditySeconds(expiration)
            .scopes("read", "write").authorizedGrantTypes("password", "refresh_token").resourceIds("resource");
}

Upvotes: 1

Related Questions