I configure WebSecurityConfig, create user in memory
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("username")
.password(passwordEncoder().encode("password"))
.authorities("READ_ORDERS")
.roles("USER");
}
configure WebSecurityConfig
#Configuration
#Order(1)
public static class BasicAuthenticationAdapter extends WebSecurityConfigurerAdapter {
private final AuthenticationEntryPoint authEntryPoint;
#Autowired
public BasicAuthenticationAdapter(AuthenticationEntryPoint authEntryPoint) {
this.authEntryPoint = authEntryPoint;
}
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/orders**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.csrf().disable()
.httpBasic().authenticationEntryPoint(authEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
When i try to Authorise with invalid credentials first time - 401 exception, it's ok.
But after successful authorization, when i use invalid username and password,
i also authorised.
What can be the problem ?
That is how basic authentication works. As soon as you have logged in successfully the valid credentials will always be posted.
Spring security works with SessionCreationPolicy, and default policy is IF_REQUIRED. It means spring creates session if it does not have and is required.
In order to solve your issue you have to change this policy.
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Restart your server and try again.
Related
I would like to configure web security layer based on my request type.
If the request starts with /rest then it should use Basic authentication with stateless session management and for login authentication then it should use CSRF with stateful session management.
I have tried below code.
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/rest/**").hasRole("SUPER_ADMIN")
.anyRequest().fullyAuthenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin().and().logout().permitAll();
}
It works with basic authentication but it doesn't work for the login request because the session is not stateful. Can anyone please help me to configure Spring security. I am new to Spring security.
You need
1. Rest API's to be authenticated by basic authentication
2. Your web application be authenticated by form login.
And authorization is other part in both cases that you can set it as per your requirement.
Let me explain what was wrong with your approach. By your approach you can achieve only one authentication entry point from one configuration. i.e, you can't achieve multiple authentication entry point.
Now coming to your first requirement of achieving multiple authentication entry point.
1. For Rest API resources -- authentication by HttpBasicAuthentication for antMatcher /rest/**
2. For WebApp resources -- authentication by Form Login for antMatcher other than /rest/**
To achieve this
1. You need to have implementation of WebSecurityConfigurerAdapter of different configuration order and different antMatcher patterns.
2. Order of each configuration is important.
- wildcard pattern(/**) should be placed last order
- non wildcard pattern or restricted pattern(/rest/**) should be placed first order
3. As those configuration classes are static and inner classes for a class which is annotated #EnableWebSecurity you should be careful while defining bean using #bean and autowiring using #Autowired.
Note:
Most of people makes mistake by not defining antmather for authorizeRequest()
If first configuration #Order(1) class is configured as below
http.authorizeRequests()
2nd configuration will become dead configuration because
http.authorizeRequests() => http.antMatcher("/**").authorizeRequests()
And all URL's will be configured only for first configuration only.
Refer code given below for better understanding.
#Configuration
#EnableWebSecurity
public class SpringSecurityConfiguration
{
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
#Configuration
#Order(1)
public static class BasicAuthSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("superadmin")
.password(passwordEncoder.encode("superadmin#123#"))
.roles("SUPER_ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.antMatcher("/rest/**")
.authorizeRequests()
.antMatchers("/rest/**").hasRole("SUPER_ADMIN")
.and().httpBasic();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
#Configuration
#Order(2)
public static class LoginFormSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder.encode("user#123#"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.antMatcher("/**") //wild card i.e, allow all (But already /rest/** is filtered by 1st config)
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/**").authenticated()
.and().formLogin()
.defaultSuccessUrl("/app/user/dashboard")
.and().exceptionHandling()
.accessDeniedPage("/403")
.and().logout()
.invalidateHttpSession(true);
http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired");
}
}
}
This question has requirement of different sets of URL's(/rest/** and other than /rest/**) for different authentication filters. Here user's (for both basic auth and form login) may be authenticated against a single table (say user_details) or multiple tables (say api_users and web_users)
If you have requirement like there is no different set of URL's but two sets of users say customer and employees(staff) both are accessing same application but they needs to be authenticated against different tables(say users and customer table) in that case refer my another answer Spring Security user authentication against customers and employee table
You have to allow users to access login page without authentication and same you can do with static pages. See below configuration.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
Agenda: To create an authorization and resource server such that.
Rest clients can authenticate and authorize and use tokens to fetch resources about the user.
this worked. accessing resources defined at /rest/user endpoint is working fine
Web clients can SSO using this authorization server
I tried using #EnableOAuth2Sso and also using #EnableOAuth2Client. Both didn't work.
When using EnableOAuth2Sso redirect to oauth server's login happened but redirection back to the app didn't happen.
Users can directly log into the authorization server and see if they have an account.
this is working but it is skipping authentication and authorization and the page is getting displayed immediately
I have a OAuth server with ResourceConfig and WebSecurityConfig
#Configuration
#EnableWebSecurity
#Order(1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired private AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired private AuthenticationFailureHandler authenticationFailureHandler;
#Autowired
#Qualifier("userAccountDetailsService")
UserAccountDetailsService userAccountDetailsService;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.csrf().disable()
.anonymous().disable()
.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.antMatchers("/**", "/css/**", "/js/**", "/images/**").permitAll()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/userPage/*").hasAnyRole("USER", "HRADMIN")
.antMatchers("/adminPage/*").hasRole("HRADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.loginProcessingUrl("/login")
.failureHandler(authenticationFailureHandler)
.successHandler(authenticationSuccessHandler)
.and()
.logout()
.logoutUrl("/logout");
// #formatter:on
}
#Autowired
protected void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userAccountDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#Configuration
#EnableResourceServer
#Order(2)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.authorizeRequests()
.antMatchers("/rest/user/**").authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
Isn't it possible to combine and use web resource and oauth resources in the same server?
I'm using
Spring Boot: 2.2.0.BUILD-SNAPSHOT and
Spring security-oauth2-autoconfigure: 2.1.3.RELEASE
The whole source is available in github
Authorization and Resource server:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-oauth
Spring Web client using EnableOAuth2Client:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-web-resource-1
Spring Web client using EnableOAuth2Sso:
https://github.com/john77eipe/SpringSecurityDrills/tree/master/securestore-web-resource-2
I am using spring boot 2.1.4 with dependencies of actuator. I wanted to configure separate authentication and authorization mechanisms for actuator and my application. I read the Multiple HttpSecurity and configured my WebSecurityAdapter as follows:
#Configuration
public class ProvisioningServiceSecurityConfiguration {
#Value("${actuator.user.name}")
private String actuatorUserName;
#Value("${actuator.password}")
private String actuatorPassword;
#Value("${actuator.role}")
private String actuatorRole;
#Bean
public UserDetailsService userDetailsService() throws Exception {
// ensure the passwords are encoded properly
UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(users.username("user").password("password").roles("ADMIN").build());
manager.createUser(
users.username(actuatorUserName).password(actuatorPassword).roles(actuatorRole).build());
return manager;
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/locations/**")
.antMatcher("/organizations/**")
.antMatcher("/productTypes/**")
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class ActuatorWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/manage/**")
.authorizeRequests()
.anyRequest().hasRole("ACTUATOR_ADMIN")
.and()
.httpBasic();
}
}
/*#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}*/
}
Note: I have disabled form Login temporarily
When I run a curl request
curl -XGET http://localhost:9797/provisioningService/organizations/all
I am able to see the output. Its as though the spring security never existed. When I enable form login, I get the spring login screen. The other behavior that I observed is if I interchange the username and password of /locations with the actuator username and password, I still get a valid response back.
I understand the form login is more of a fallback but I want to disable the form login (probably we may move to cas) and use authentication and authorization only based on the spring security httpBasic. I am not able to understand the mistake I am making.
My requirement is finally :
1) a request to /organizations or /locations etc should be accessible only if the username password is "user" and "password"
2) a request to /manage which is the actuator api should be accessible only if the username and password and role matches with the actuator username and password.
3) Any other API can be permitAll / form login
How do i go about achieving this?
1) Spring Security has a function to control access by filtering by Authorities(after Authentication), but there is no function to filter by the information required for login. You need business logic to verify that you are attempting to log in with the corresponding ID and password during login.
2) As mentioned above, access control with ID and password is not provided.
I recommend creating Authorities for only the two accounts you requested.
3) .antMatcher("/form").permitAll()
I am creating an API using Spring Boot Rest, I want to restrict the API so only logged in users can access it. Now to test the API I am using postman, but how to pass the user details to the API?
Here is my code:
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/orders").permitAll()
.antMatchers(HttpMethod.POST, "/order/**").hasAnyRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/order/**").hasAnyRole("ADMIN")
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
// create two users, admin and user
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN");
}
}
Here is my access denied handler:
#Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
private static Logger logger = LoggerFactory.getLogger(MyAccessDeniedHandler.class);
#Override
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AccessDeniedException e) throws IOException, ServletException {
Authentication auth
= SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
logger.info("User '" + auth.getName()
+ "' attempted to access the protected URL: "
+ httpServletRequest.getRequestURI());
}
httpServletResponse.setContentType("application/json");
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
outputStream.print("Wrong user");
}
}
When I try to access the API with URL as order and method as DELETE using postman and passing user login details using Authorization tab with Basic Auth and passing Username as admin and password as password, I am getting Wrong user message.
How to pass the user loin details to my API using postman?
Maybe form login is the default auth mechanism and you need to specify that you want to use Basic Auth.
Try this:
#Configuration
class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/", "/orders").permitAll()
.antMatchers(HttpMethod.POST, "/order/**").hasAnyRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/order/**").hasAnyRole("ADMIN")
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler)
.and() //added
.httpBasic(); //added
}
// create two users, admin and user
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("ADMIN");
}
}
What you need is the following dependency (You might have it already):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Than you can create a user in your application.properties file:
security.user.name=username
security.user.password=password
If you are using Spring 2.0.0 M4 or higher use "spring.security".
Now go to Postman under "Authorization" use "Basic Auth" and fill in the credenrtials you have set in the properties file.
Hope this is what you are looking for. Good luck:)
I am writing an application using Spring Security.
I've implemented my custom UserDetails, UserDetailsService, AccessDecisionVoter and WebSecurityConfigurerAdapter.
I want to permit unauthorized users to access the /authenthication/login page to log in, but every other access to a page needs to be handled by the custom AccessDecisionVoter.
My custom WebSecurityConfigurerAdapter class looks like this:
#Configuration
#EnableWebSecurity
#ComponentScan(value = "security")
public class Configuration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/authentication/login**")
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.accessDecisionManager(accessDecisionManager())
;
}
#Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters =
Arrays.asList(new AccessDecisionVoterImpl());
return new UnanimousBased(decisionVoters);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(userDetailsServiceImpl);
} catch (Exception e) {
e.printStackTrace();
}
}
#Bean
public UserDetailsServiceImpl userDetailsService() {
return userDetailsServiceImpl;
}
}
I have defined several roles in my database. The vote method in my custom AccessDecisionVoter retrieves the permissions of the User that is logged in and grants or denies access, based on that and the URL + httpMethod.
Problem:
However when I send a POST to the /authentication/login with the username and password my code gives me a NullPointerException in the custom AccessDecisionVoter: the username (retrieved via the authentication.getPrincipal(); returns anonymousUser, which results in the NullPointer later in the code. But I don't understand why the vote method gets called anyway since the configuration file told Spring to permittAll accesses to /authentication/login
I believe that the way you have it set up, permitAll just makes it so that all requests are allowed (even unauthenticated ones) but it doesn't disable the security chain for that request, it will still try to process through them all. If you just want to bypass all the security, the approach i usually use is to override the webSecurity config method and add the exception cases there, like so:
#Override
public void configure(WebSecurity webSecurity) throws Exception
{
webSecurity
.ignoring()
.antMatchers("/authentication/login**");
}