I'm setting up my Spring Security (v4.0.1) web application. I want to have two authentication providers, an "in-memory" one to manage the administrator account and a custom one which refers to my own implementation. The system should attempt the authentication against the "in-memory" provider first of all and against the custom one in second place. My code looks like this:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
AuthenticationProvider provider) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password("s3cr3t")
.authorities("ADMIN");
auth.authenticationProvider(provider);
}
However, this code leads the framework to try my custom implementation first. It makes a bit of sense, since the AuthenticationManagerBuilder#authenticationProvider method adds a Provider to the internal List while the AuthenticationManagerBuilder#inMemoryAuthentication one configures it internally. How could I manage to get it work?
You can create your InMemoryUserDetailsManagerConfigurer manually and tell it to configure itself on the AuthenticationManagerBuilder when you have finished configuring it so it installs it's AuthenticationProvider before your custom one:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
AuthenticationProvider provider) throws Exception {
inMemoryConfigurer()
.withUser("admin")
.password("s3cr3t")
.authorities("ADMIN")
.and()
.configure(auth);
auth.authenticationProvider(provider);
}
private InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
inMemoryConfigurer() {
return new InMemoryUserDetailsManagerConfigurer<>();
}
Normally what happens is that the InMemoryUserDetailsManagerConfigurer is created and added to the list of configurers that should be applied when the AuthenticationManager is built - which is after you've installed your custom AuthenticationProvider.
More or less from spring.io Documentation
If you are using XML configuration (e.g. spring-security.xml):
<security:authentication-manager>
<security:authentication-provider ref="FirstProvider" />
<security:authentication-provider ref="SecondProvider" />
</security:authentication-manager>
(I am using that setup for one of Spring's built-in authentication provider next to a custom one, works fine)
If you are using Java Config, I can only reference some other person's post maclema on Java config for multiple authentication provider, since I have never (successfully) tried code config
Today we tend to configure Spring Security via WebSecurityConfigurerAdapter, you register filters that extract credentials from a request and register providers that use tokens built by filters by populating Authentication object with other details like authorities:
#Override
protected void configure(HttpSecurity http) throws Exception {
AbstractPreAuthenticatedProcessingFilter tokenPreAuthProcessingFilter = new RequestHeaderAuthenticationFilter();
http.addFilterAfter(tokenPreAuthProcessingFilter, SecurityContextPersistenceFilter.class);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// First.
auth.authenticationProvider(new PreAuthenticatedAuthenticationProvider());
// Second.
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser(...);
}
Related
This is my Security config
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/assets/**", "/register/**", "/","/login**")
.permitAll().antMatchers("/profile/**").hasAuthority("ROLE_1").anyRequest().authenticated()
.antMatchers("/actuator/**").hasAuthority("ROLE_2").anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.and().sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true).expiredUrl("/login?expired")
.and().and().logout().deleteCookies("JSESSIONID").invalidateHttpSession(true)
.and().csrf().disable();
// .failureUrl("/fail");
}
This is to add HttpSessionEventPublisher into app context
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
Please let me know what I am missing. I am still able to login from two browsers using same credentials.
I found the solution. It is to override equals and hashCode methods of my User class which implements UserDetails based on below solutions. Comparison of UserDetails objects for authenticated principals is how session concurrency is controlled / measured
http://forum.spring.io/forum/spring-projects/security/99166-maximum-sessions-1-does-not-work
Spring Security maxSession doesn't work
Spring 2.0.3.RELEASE
Goal: Implement Spring Boot Security (basic auth for starters) on all endpoints except /actuator/health, /actuator/info and /ping (a custom controller that just returns ResponseEntity.status(HttpStatus.NO_CONTENT).build()).
The below gives me a 401. Any combination seems to either give me complete anonymous access to all endpoints or 401 to all.
I've set the spring.security.user.name and ...password in application.yml and it is working correctly.
I've implemented...
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
// just trying to get health working for starters
http.authorizeRequests().antMatchers("/actuator/health").permitAll()
.anyRequest().authenticated()
.and().formLogin().permitAll();
}
}
The below seemed like it was restricted to Actuator's /health and /info endpoints, but instead is also opening up my custom /ping endpoint as well (it's not in this list).
http.requestMatcher(EndpointRequest.to("health", "info"))
.authorizeRequests().anyRequest().permitAll();
The issue ended up being a bug in Spring Tool Suite. Using Boot Dashboard with a Gradle project wasn't always picking up build output. It seems to be using a different directory and I cannot figure it out.
The HttpSecurity configuration that ended up working for me was:
#Override
protected void configure(final HttpSecurity http) throws Exception {
// #formatter:off
http.
authorizeRequests().
antMatchers("/ping", "/actuator/health", "/actuator/info", "/login").permitAll().
anyRequest().authenticated().and().
httpBasic().and().
// CSRF tokens for API access
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// #formatter:on
}
I try to modify existing example - Tonr2 and Sparklr2.
Also I viewed this tutorial based on Spring Boot Spring Boot OAuth2. I try to build application like in Tonr2 example but without first login (on tonr2). I just need one Authentication on Sparklr2 side. I do this:
#Bean
public OAuth2ProtectedResourceDetails sparklr() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setId("sparklr/tonr");
details.setClientId("tonr");
details.setTokenName("oauth_token");
details.setClientSecret("secret");
details.setAccessTokenUri(accessTokenUri);
details.setUserAuthorizationUri(userAuthorizationUri);
details.setScope(Arrays.asList("openid"));
details.setGrantType("client_credentials");
details.setAuthenticationScheme(AuthenticationScheme.none);
details.setClientAuthenticationScheme(AuthenticationScheme.none);
return details;
}
But I have Authentication is required to obtain an access token (anonymous not allowed) . I checked this question. Of course, my user is anonymous - I want to login on Sparklr2. Also, I tried different combinations of settings of this bean, but nothing good. How to fix it? How to make it work as I want?
Almost two years late for the post.
The exception is thrown from AccessTokenProviderChain
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth instanceof AnonymousAuthenticationToken) {
if (!resource.isClientOnly()) {
throw new InsufficientAuthenticationException(
"Authentication is required to obtain an access token (anonymous not allowed)");
}
}
You either
Use ClientCredentialsResourceDetails in your OAuth2RestTemplate, or
Authenticate the user before using AuthorizationCodeResourceDetails to access external resources
In fact, in the tonr2 and sparklr2 example (I personally find the name very confusing), to access resources on sparklr2, a user has to first authenticate on tonr2. As seen in oauth2/tonr:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("marissa").password("wombat").roles("USER").and().withUser("sam")
.password("kangaroo").roles("USER");
}
If your user is anonymous, you might want to check for Single Sign On.
For whoever just want to quickly try out Oauth2 integration, add basic auth to your application:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated().and().httpBasic();
}
application.properties:
spring.security.user.password=password
spring.security.user.name=user
Don't forget to add spring-boot-starter-security to your project.
e.g. In gradle: compile 'org.springframework.boot:spring-boot-starter-security'
Or you can also disable AnonymousAuthenticationToken from creating by:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().disable();
}
Old post...
The exception indeed is thrown form AccessTokenProviderChain but it happens when spring security filters invoking if incorrect order. Make sure that your OpenIdAuthenticationFilter is invoking after OAuth2ClientContextFilter.
I've followed this and this tutorial to create a skeleton of an Angular.JS application with a Java-based backend. Its code can be found here.
It has authentication - at the start Spring boot writes to the console a random password, which you can use to login to the started application. User name is user and the password is printed in the console at the start:
Now I want to have several user accounts with fixed passwords (it's OK, if they are hardcoded).
How can I do this in that application without breaking compatibility with AngularJS?
I suppose that I have to modify SecurityConfiguration in UiApplication and use something like
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
as explained here, but I'm not sure that it won't break AngularJS.
That's the solution:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfiguration extends
WebSecurityConfigurerAdapter {
#Autowired
public void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1")
.password("password1")
.roles("ADMIN")
.and()
.withUser("user2")
.password("password2")
.roles("USER");
}
As long as you don't change the authentication scheme (i.e. BASIC, FORM etc.), AngularJS doesn't care about how you manage the user accounts in the backend. Of course if you would have used a fixed user and password and have it hardcoded in the AngularJS code, you would have to change this.
It wouldn't break the angular compatibility. But in addition to the code change you mentioned, you would also need to make sure that you are allowing access to /login URI anonymously. Change in your overloaded configure method would also be required, something as follows:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/login.html").permitAll()
.antMatchers("/index.html", "/home.html").authenticated()
.antMatchers("/index.html", "/home.html").hasRole("USER")
.anyRequest().authenticated();
}
I am having a difficult time figuring out how to wire up spring security without forcing authentication. My specific app does not require the user to authenticate but the user can authenticate if they want.
I currently have a WebSecurityConfigurerAdapter set up that you can see at the end of this post. With this setup I'm getting a 403 on all /api/* requests and /j_spring_security_check.
Could someone please help me either fix my existing config or point me to a working example that accomplishes this?
Every example I see out there seems to require the user to authenticate and if they don't it throws a 403. In my app, I'm just using it to establish a session and at this point all users should be able to access all end points regardless of if they are authenticated or not.
WebSecurityConfig
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ItAuthenticationProvider customAuthenticationProvider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/**").permitAll()
.antMatchers("/j_spring_security_check").permitAll()
.and().formLogin()
.loginProcessingUrl("/j_spring_security_check")
.defaultSuccessUrl("/successful.html")
.loginPage("/#login")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/successful.html");
}
}
You can take a look at this sample Spring Security application we built with Stormpath support. In this example, the home screen does not require authentication. Furthermore, the information that is displayed there is dynamically calculated based on whether the user is authenticated or not.
If I understand your requirement, you can use the anonymous authentication.
The documentation can be found here