Spring Boot and Spring Cloud Security OAUTH 2 SSO Failing with latest releases - spring

I am trying to upgrade a sample Spring Boot and Spring Cloud Security with OAuth from Spring Boot 1.4.1 + Brixton.RELEASE to Spring Boot 1.5.3+ Dalston.RELEASE. However, it has been a long hard try without any success.
It seems for some reason the resource server security filter chain is not getting fired. As a result the call to "/me" or "/user" is being handled by default security filter chain. I am thinking if this is a problem with order. But tried to explicitly set the order of the security filter chains as follows
Auth Server 6
Web Default 5
Resource server 3 (hard coded ??)
Since the default filter chain is handling the request, it is always going to the login page, which generates HTML and the SSO client (server side thymeleaf web UI) fails.
The source code is below
Authorization server
#SpringBootApplication
public class MyAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(MyAuthServerApplication.class, args);
}
}
Then the authorization server configuration
#Configuration
#EnableAuthorizationServer
#Order(6)
public class AuthorizationServerConfigurer extends A
uthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
clients.inMemory()
.withClient("myauthserver")
.secret("verysecretpassword")
.redirectUris("http://localhost:8080/")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("myscope")
.autoApprove(true);
}
}
Then the resource server class
#Configuration
#EnableResourceServer
public class ResourceServerConfigurer extends
ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
The web MVC configuration
#Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("login").setViewName("login");
}
}
The default spring security configuration
#Configuration
#EnableWebSecurity
#Order(9)
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
The resource controller
#RestController
public class ResourceController {
#RequestMapping(value = { "/user" }, produces = "application/json")
public Map<String, Object> user(OAuth2Authentication user) {
Map<String, Object> userDetails = new HashMap<>();
userDetails.put("user", user.getUserAuthentication().getPrincipal());
userDetails.put("authorities",
AuthorityUtils.
authorityListToSet(user.getUserAuthentication().getAuthorities()));
return userDetails;
}
}
Finally the configuration - application.yml for the auth server
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
The login.html Thymeleaf template is not shown here.
OAUTH 2 SSO Client Web App
#SpringBootApplication
public class MyWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(MyWebsiteApplication.class, args);
}
}
The web security configuration
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll() // Allow navigating to index
page,
.anyRequest().authenticated(); // but secure all the other URLs
}
}
The web controller
#Controller
public class MyWebsiteController {
/**
* Default index page to verify that our application works.
*/
#RequestMapping("/")
#ResponseBody
public String helloWorld() {
return "Hello world!";
}
/**
* Return a ModelAndView which will cause the
'src/main/resources/templates/time.html' template to be rendered,
* with the current time.
*/
#RequestMapping("/time")
public ModelAndView time() {
ModelAndView mav = new ModelAndView("time");
mav.addObject("currentTime", getCurrentTime());
return mav;
}
private String getCurrentTime() {
return LocalTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
}
}
The application configuration - application.yml for the client web app
server:
port: 8080
contextPath: /
security:
oauth2:
client:
accessTokenUri: http://localhost:9090/auth/oauth/token
userAuthorizationUri: http://localhost:9090/auth/oauth/authorize
clientId: myauthserver
clientSecret: verysecretpassword
resource:
userInfoUri: http://localhost:9090/auth/user
The Thymeleaf template for the time.html page is not shown here.
There must be some subtle little configuration thats wrong or some bug I do not know. Any help or ideas highly appreciated.

Solution
Guess was right the ordering of the security filter chain got was changed. Here is the link to the
Spring 1.5.x release note
Modified code is here and will upload it to Github later. All changes on the auth server configuration.
The Spring security configuration - remove the #Order annotation.
#Configuration
#EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
Then change the application.yml as follows
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
security:
oauth2:
resource:
filter-order : 3
That's it then the time is displayed on the client application /time url after authentication on the auth server.

Related

An expected CSRF token cannot be found

I'm trying to disable Spring security into latest Spring Cloud using this configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
#Order(SecurityProperties.DEFAULT_FILTER_ORDER)
public class WebSecurityConfigSec extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable()
.authorizeRequests().anyRequest().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/**");
}
}
application.yml
spring:
main:
allow-bean-definition-overriding: true
security:
ignored=/**:
enable-csrf: false
I also tried to add:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}
But it's not working.
I get error: An expected CSRF token cannot be found
18:16:24.537 [boundedElastic-2] DEBUG DefaultWebSessionManager[lambda$createWebSession$3:94] - Created new WebSession.
18:16:24.540 [boundedElastic-2] DEBUG HttpWebHandlerAdapter[traceDebug:91] - [1ffd0a30] Completed 403 FORBIDDEN
Do you know how I can solve this issue?
Exclude the MVC dependencies from pom.xml
And add:
spring:
main:
web-application-type: reactive
This worked for me; I was getting CSRF error as spring security used in Spring MVC was enabled.
I Fixed this by
#Bean
SecurityWebFilterChain springSecurityFilterChain(
ServerHttpSecurity http,
ReactiveClientRegistrationRepository clientRegistrationRepository
){
return http
...
.csrf(csrf -> csrf.csrfTokenRepository(
CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
.build();
}
#Bean
WebFilter csrfWebFilter() {
//A filter with the only purpose of subscribing to the CsrfToken reactive stream and ensuring its value is extracted correctly
return (exchange, chain) -> {
exchange.getResponse().beforeCommit(() -> Mono.defer(() -> {
Mono<CsrfToken> csrfToken =
exchange.getAttribute(CsrfToken.class.getName());
return csrfToken != null ? csrfToken.then() : Mono.empty();
}));
return chain.filter(exchange);
};
}

Authentication provider per url pattern - Spring Boot

I faced problem when configuring different auth providers per url pattern using Spring Boot security. I am trying to configure security in Spring Boot app and want to have swagger behind basic auth and all API is secured only by token. I have it almost working, but noticed that API except the fact that it is secured by token which is verified by IDAuthProvider class it also is secured by basic auth. I do not want that and also noticed that if I removed line:
sessionCreationPolicy(SessionCreationPolicy.STATELESS).
it seems to be working correctly, but still header Basic {token} is being added in request which is something I do not want...
Do you know how can I configure it to make all swagger stuff secured by basic auth and API stuff secured by token?
My configuration looks like below:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public class SwaggerSecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationProvider userPassAuthProvider;
#Autowired
SwaggerSecurityConfig(UserPassAuthProvider userPassAuthProvider) {
this.userPassAuthProvider = userPassAuthProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/swagger**").
authorizeRequests().
antMatchers("/swagger**").authenticated().
and().httpBasic().and().csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(userPassAuthProvider);
}
}
#Configuration
#Order(2)
public class APISecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationProvider idAuthProvider;
#Autowired
APISecurityConfig(IDAuthProvider idAuthProvider) {
this.idAuthProvider = idAuthProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/v1/**").
authorizeRequests().anyRequest().authenticated().
and().
addFilterBefore(idpAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class).sessionManagement().
and().
csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(idAuthProvider);
}
IDPAuthenticationFilter idpAuthenticationFilter(AuthenticationManager auth) {
return new IDPAuthenticationFilter(auth, new OrRequestMatcher(new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.GET.toString()), new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.POST.toString()), new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.DELETE.toString()), new AntPathRequestMatcher("/swagger**", HttpMethod.GET.toString())));
}
}
}

Springboot 2 Oauth2 cannot redirect to SSO client

I'm current working on the implementation of Springboot 2.x oauth2. But I got some tricky problems.
The project comprises both auth-server and sso-client (GitHub link is provided in the bottom). The problem is: when I entered a protected URL (eg localhost:9000/) it will be redirected to the login page configured in the auth-server. However, it won't redirect back to sso-client after successful login.
Authorization server config for auth-server:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private AuthenticationManager authenticationManager;
public AuthorizationServerConfig(AuthenticationConfiguration authenticationConfiguration) throws Exception {
this.authenticationManager = authenticationConfiguration.getAuthenticationManager();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
super.configure(security);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("all")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
Security config for auth-server:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("root")
.password(passwordEncoder().encode("root"))
.roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf().disable();
}
}
Security config for sso-client:
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.anyRequest().authenticated();
}
}
application.yml for sso-client:
auth-server: http://localhost:9090
server:
port: 9000
security:
oauth2:
client:
client-id: client
client-secret: secret
scope: all
user-authorization-uri: ${auth-server}/oauth/authorize
access-token-uri: ${auth-server}/oauth/token
resource:
token-info-uri: ${auth-server}/oauth/check_token
preferTokenInfo: false
Here is the link to this project: https://github.com/paul8263/SpringBoot2Oauth2
PS: I made it work with spring boot 1.5.8: https://github.com/paul8263/SsoDemo2
I compared the codes with Springboot2 (first link) but I barely noticed any obvious difference.
Could someone help me solve this problem by making the simple demo working? Many thanks.

Is it a Spring `Dalston` bug? [duplicate]

I am trying to upgrade a sample Spring Boot and Spring Cloud Security with OAuth from Spring Boot 1.4.1 + Brixton.RELEASE to Spring Boot 1.5.3+ Dalston.RELEASE. However, it has been a long hard try without any success.
It seems for some reason the resource server security filter chain is not getting fired. As a result the call to "/me" or "/user" is being handled by default security filter chain. I am thinking if this is a problem with order. But tried to explicitly set the order of the security filter chains as follows
Auth Server 6
Web Default 5
Resource server 3 (hard coded ??)
Since the default filter chain is handling the request, it is always going to the login page, which generates HTML and the SSO client (server side thymeleaf web UI) fails.
The source code is below
Authorization server
#SpringBootApplication
public class MyAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(MyAuthServerApplication.class, args);
}
}
Then the authorization server configuration
#Configuration
#EnableAuthorizationServer
#Order(6)
public class AuthorizationServerConfigurer extends A
uthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
clients.inMemory()
.withClient("myauthserver")
.secret("verysecretpassword")
.redirectUris("http://localhost:8080/")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("myscope")
.autoApprove(true);
}
}
Then the resource server class
#Configuration
#EnableResourceServer
public class ResourceServerConfigurer extends
ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
The web MVC configuration
#Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("login").setViewName("login");
}
}
The default spring security configuration
#Configuration
#EnableWebSecurity
#Order(9)
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
The resource controller
#RestController
public class ResourceController {
#RequestMapping(value = { "/user" }, produces = "application/json")
public Map<String, Object> user(OAuth2Authentication user) {
Map<String, Object> userDetails = new HashMap<>();
userDetails.put("user", user.getUserAuthentication().getPrincipal());
userDetails.put("authorities",
AuthorityUtils.
authorityListToSet(user.getUserAuthentication().getAuthorities()));
return userDetails;
}
}
Finally the configuration - application.yml for the auth server
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
The login.html Thymeleaf template is not shown here.
OAUTH 2 SSO Client Web App
#SpringBootApplication
public class MyWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(MyWebsiteApplication.class, args);
}
}
The web security configuration
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll() // Allow navigating to index
page,
.anyRequest().authenticated(); // but secure all the other URLs
}
}
The web controller
#Controller
public class MyWebsiteController {
/**
* Default index page to verify that our application works.
*/
#RequestMapping("/")
#ResponseBody
public String helloWorld() {
return "Hello world!";
}
/**
* Return a ModelAndView which will cause the
'src/main/resources/templates/time.html' template to be rendered,
* with the current time.
*/
#RequestMapping("/time")
public ModelAndView time() {
ModelAndView mav = new ModelAndView("time");
mav.addObject("currentTime", getCurrentTime());
return mav;
}
private String getCurrentTime() {
return LocalTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
}
}
The application configuration - application.yml for the client web app
server:
port: 8080
contextPath: /
security:
oauth2:
client:
accessTokenUri: http://localhost:9090/auth/oauth/token
userAuthorizationUri: http://localhost:9090/auth/oauth/authorize
clientId: myauthserver
clientSecret: verysecretpassword
resource:
userInfoUri: http://localhost:9090/auth/user
The Thymeleaf template for the time.html page is not shown here.
There must be some subtle little configuration thats wrong or some bug I do not know. Any help or ideas highly appreciated.
Solution
Guess was right the ordering of the security filter chain got was changed. Here is the link to the
Spring 1.5.x release note
Modified code is here and will upload it to Github later. All changes on the auth server configuration.
The Spring security configuration - remove the #Order annotation.
#Configuration
#EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
Then change the application.yml as follows
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
security:
oauth2:
resource:
filter-order : 3
That's it then the time is displayed on the client application /time url after authentication on the auth server.

Spring Boot LDAP Authentication: Always get bad credentials

I'm trying to authenticate with a Spring Boot application against an Active Directory server in my local network, but I don't know what could I be doing wrong.
When I access localhost I am redirected to the login page:
Whenever I write any real user credentials, I'm redirected to the same page with an error message:
If I send a random word as user and password I get the same login error screen, but additionaly this message is shown from Eclipse console:
2016-02-04 18:54:47.591 INFO 10092 --- [nio-8080-exec-8] ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: Supplied password was invalid
From the Active Directory Server, the distinguishedName of the group that I want to access is: CN=Bulnes,OU=Usuarios Locales,DC=Bulnes,DC=local, so it is configured in security configuration class like this:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**").permitAll()
.anyRequest().fullyAuthenticated()
.and()
.formLogin();
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
ActiveDirectoryLdapAuthenticationProvider provider=
new ActiveDirectoryLdapAuthenticationProvider("bulnes.local"
,"ldap://192.168.1.3:389/"
,"CN=Bulnes,OU=Usuarios Locales,DC=Bulnes,DC=local");
auth.authenticationProvider(provider);
}
}
}
This is how I have it working:
ad.properties
ad.url=ldap://yourserver.abc.com:389
ad.domain=abc.com
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${ad.domain}")
private String adDomain;
#Value("${ad.url}")
private String adUrl;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login", "/css/**", "/public/**").permitAll().anyRequest().authenticated()
.and().formLogin().loginPage("/login").defaultSuccessUrl("/", true)
.failureUrl("/login?failed=badcredentials")
.permitAll().and().logout().logoutUrl("/logout")
.logoutSuccessUrl("/login");
}
#Bean
#Override
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(adDomain,
adUrl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
}
Just created the provider like this, and it works fine.
ActiveDirectoryLdapAuthenticationProvider provider=
new ActiveDirectoryLdapAuthenticationProvider("bulnes.local"
,"ldap://192.168.1.3:389);
It still gives an exception but at least authenticates
2016-02-04 21:30:36.293 INFO 12056 --- [nio-8080-exec-3] o.s.s.ldap.SpringSecurityLdapTemplate : Ignoring PartialResultException

Resources