lor lor
lor lor

Reputation: 121

Set basic auth on server side

I configured resource and authorization servers in one application. I use spring-security oauth2, with Resource Owner Password Credentials. Can I set up basic auth on the server side? I don't want to do it on the front-end. I don't know what a part of the code I need to show... When I want to receive a token I need to enter this in postman: from postman Can I configure it on the server side?

Authorization Server:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private JwtAccessTokenConverter jwtTokenEnhancer;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).tokenEnhancer(jwtTokenEnhancer).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager)
                .pathMapping("/oauth/token", "/login");
    }
}

Resource Server:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "resource_id";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(RESOURCE_ID).stateless(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .cors().and().csrf().disable()

                .authorizeRequests()
                .antMatchers("/swagger-ui.html#").permitAll()
                .antMatchers("/").authenticated()
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }
}

Security config:

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

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10);
    }


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


    @Override
    public void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);
    }


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

    @Bean
    protected JwtAccessTokenConverter jwtTokenEnhancer() {
        converter.setSigningKey("Demo-Key-1");
        return converter;
    }

    @Bean
    @Autowired
    public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore);
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    @Autowired
    public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore);
        return store;
    }

    @Override
    @Order(Ordered.HIGHEST_PRECEDENCE)
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/resources/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
                .and().cors().and().csrf().disable();
    }
}

Upvotes: 0

Views: 937

Answers (1)

Filip Hanik VMware
Filip Hanik VMware

Reputation: 1622

This answer is accompanied by a complete and working sample.

Maybe you are biting off more than you can chew here?

For example:

.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()

The /oauth/token endpoint must remain protected. This is the endpoint on the authorization server that issues tokens to authenticated clients. The system will probably fail with NullpointerException or other exceptions if you open it, however, the above configuration option indicate that maybe you're a bit confused about how OAuth2 works.

What I would recommend is to first fully understand authorization server versus resource server. You can definitely combine the two, but they would have very different endpoints.

Authorization Server - typical endpoints

/oauth/token - issues tokens
/oauth/authorize - issues authorization codes
/introspect - validates a token and returns token claims in a known format

Resource Server - These would be your application endpoints, requiring Bearer tokens, for example

/account/123/debit

and these endpoints expect a stateless request that has an authorization header

Authorization: Bearer <token value here>

A controller for a resource server would look like this:

@PreAuthorize("hasRole('your-scope-role')")
@RequestMapping(value = "/hello")
@ResponseBody
public String hello(Principal principal) {
    return "Hello to " + principal.getName();
}

Feel free to review the simple project that I have created for you.

In addition to that, I also recommend this video on OAuth2 and OpenID Connect

In my sample, I have configured the clients like this:

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        InMemoryClientDetailsService clientDetails = new InMemoryClientDetailsService();
        BaseClientDetails client = new BaseClientDetails(
            "testclient",
            null,
            "testscope,USER,ADMIN",
            "password",
            null
        );
        client.setClientSecret(passwordEncoder.encode("secret"));
        clientDetails.setClientDetailsStore(
            Collections.singletonMap(
                client.getClientId(),
                client
            )
        );
        clients.withClientDetails(clientDetails);
    }

Take a look at this simple test case, the client is using http-basic authentication:

mvc.perform(
    post("/oauth/token")
            .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
            .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
            .param("username", "admin")
            .param("password", "password")
            .param("grant_type", "password")
            .param("response_type", "token")
            .param("client_id", "testclient")
            .header("Authorization", "Basic " + Base64.encodeBase64String("testclient:secret".getBytes()))

This is client authentication, using the http-basic method:

.header("Authorization", "Basic " + Base64.encodeBase64String("testclient:secret".getBytes()))

Upvotes: 2

Related Questions