Spring security : managing two Authentication Provider - java

I need to have 2 implementations of AuthenticationProvider required for spring security.
One is WindowsAuthenticationProvider (retrieve the user logged in windows - through waffle connector)
So I configure like this :
#Configuration
#EnableWebSecurity
public class WaffleConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
//basic auth for rest endpoint callers
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.authenticationProvider(inMemoryAuthenticationProvider)
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//waffle for spring mvc users (with prime faces)
.and()
.antMatcher("/secure/**")
.authorizeRequests()
.antMatchers("/secure/**").authenticated()
.and()
.authenticationProvider(windowsAuthProvider)
.httpBasic()
.authenticationEntryPoint(negotiateSecurityFilterEntryPoint)
.and()
.addFilterBefore(negotiateSecurityFilter, BasicAuthenticationFilter.class);
}
}
The problem is this line :
.authenticationProvider(inMemoryAuthenticationProvider)
I just want to do like my inmemory authentication :
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
GrantedAuthority ga = new GrantedAuthority() {
#Override
public String getAuthority() {
return "eligibilite:read";
}
};
GrantedAuthority gaw = new GrantedAuthority() {
#Override
public String getAuthority() {
return "eligibilite:write";
}
};
auth.inMemoryAuthentication()
.withUser("francois")
.password("{noop}fournel")
.authorities(Arrays.asList(ga))
.and()
.withUser("francois2")
.password("{noop}fournel2")
.authorities(Arrays.asList(gaw));
}
For windows connection through waffle I already defined the auth provider :
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(windowsAuthProvider)
}
I need to define the "In memory authentication provider", but I don't know how to define and create this object.

Related

Spring boot security to allow all endpoints except one

For a project that has no spring security. All controllers (GET/POST) of the project are not secured and should stay unsecured. But now, I have a new Controller and i want to secure its path (/private), sub-pathes and parameters. Only this one path must be secured with Basic Authentication. Why is my code not working?
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.antMatchers("/private**").hasAuthority("ADMIN").and().httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("{noop}pass")
.roles("ADMIN");
}
}
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/private").hasRole("ADMIN")
.antMatchers("/private/**").hasRole("ADMIN")
.antMatchers("/**").permitAll()
.and()
.httpBasic();
or
http.csrf()
.disable()
.authorizeRequests()
.antMatchers("/private").hasRole("ADMIN")
.antMatchers("/private/**").hasRole("ADMIN")
.anyRequest().permitAll()
.and()
.httpBasic();

Spring Security with Multiple Authentications

hi how i can use this orders for my controller and restController ....
like -> order 1 for html view and order 2 for rest api
i want use it for webapp using rest and mvc in spring
Multiple Entry Points With Multiple HTTP Elements
i think i should using order in my controller class!
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/**").hasRole("EMPLOYEE")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/LoginPage")
.loginProcessingUrl("/authenticateTheUser")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout().permitAll() `enter code here`
.and()
.exceptionHandling().accessDeniedPage("/access-denied");
}
}
#Configuration
#Order(2)
public class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(m.authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/**").hasRole("EMPLOYEE")
.and()
.httpBasic()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
}
i work on this problem and find way for using spring rest api and spring mvc in single
project this is easy to use them in one project with out security
for spring rest security and spring mvc security with login page and rest basic auth registery in a project we should use httpBasic()
and for url use
http://username:password#localhost:8080/api/members/
#Configuration
#EnableWebSecurity
public class MultipleEntryPointsSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
// this is filter for mappings for api and mvc mappings
// http://username:password#localhost:8080/api/members/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasRole("EMPLOYEE")
.antMatchers("/leaders/**").hasRole("MANAGER")
.antMatchers("/systems/**").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/api/**").hasRole("EMPLOYEE")
.and()
.httpBasic()
.and()
.formLogin()
.loginPage("/showMyLoginPage")
.loginProcessingUrl("/authenticateTheUser")
.successHandler(customAuthenticationSuccessHandler)
.permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/access-denied");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService); //set the custom user details service
auth.setPasswordEncoder(passwordEncoder()); //set the password encoder - bcrypt
return auth;
}
}

Issue with having multiple WebSecurityConfigurerAdapter in spring-boot

I am using spring-boot-1.5.10 and spring-boot-starter-security.
In my microservice, I am exposing API's to the external world and internal microservices.
so I would like to 2-kind of security. one for external calls and other for internal calls.
I have referred this URL and tried to implement multiple security adapters in my application.
But no luck it's always picking the internal one instead of external one,
Please find the security adapter for your reference,
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired(required = false)
ServiceWebSecurityConfigurer serviceWebSecurityConfigurer;
// #Override
// public void configure(WebSecurity web) throws Exception {
// web
// .ignoring()
// .antMatchers(HttpMethod.PUT,"/v1/emp/**")
// .antMatchers(HttpMethod.DELETE,"/v1/emp/**");
// }
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(new ExternalApiAuthenticationProvider())
.securityContext()
.securityContextRepository(new ExternalApiSecurityContextRepository())
.and()
.exceptionHandling()
.authenticationEntryPoint(new ApiAuthenticationEntrypoint())
.and()
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/v1/**").fullyAuthenticated();
if(serviceWebSecurityConfigurer != null)
serviceWebSecurityConfigurer.configure(http);
http.authenticationProvider(new InternalApiAuthenticationProvider())
.securityContext()
.securityContextRepository(new InternalApiSecurityContextRepository())
.and()
.exceptionHandling()
.authenticationEntryPoint(new ApiAuthenticationEntrypoint())
.and()
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.PUT,"/v1/emp/**").fullyAuthenticated()
.antMatchers(HttpMethod.DELETE,"/v1/emp/**").fullyAuthenticated();
}
}
It always picks the "InternalApiSecurityContextRepository" even the external API's using internal security.
It seems the later is overriding the former.
UPDATE-1(as per Gaurav Srivastav answer)
External API call security adapter :
#EnableWebSecurity
public class WebSecurityConfig {
#Configuration
#Order(2)
public static class InternalSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(new InternalApiAuthenticationProvider())
.securityContext()
.securityContextRepository(new InternalApiSecurityContextRepository())
.and()
.exceptionHandling()
.authenticationEntryPoint(new InternalApiAuthenticationEntrypoint())
.and()
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.PUT,"/v1/emp/**").fullyAuthenticated()
.antMatchers(HttpMethod.DELETE,"/v1/emp/**").fullyAuthenticated();
}
}
#Configuration
#Order(1)
public static class ExternalSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authenticationProvider(new ExternalApiAuthenticationProvider())
.securityContext()
.securityContextRepository(new ExternalApiSecurityContextRepository())
.and()
.exceptionHandling()
.authenticationEntryPoint(new ApiAuthenticationEntrypoint())
.and()
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/v1/**").fullyAuthenticated();
}
}
}
It works for External(Since the order is 1) but for internal we are getting the following exception and it is using the External configuration security context,
An internal server error occurred.Message:An Authentication object was not found in the SecurityContext
I think the problem here is, we cannot use 2-security context it seems.Is there anyway to use different security context?
Any hint would be really appreciable to solve the issue.
Thanks in Advance.
You have define more than one configuration and specify the order using #Order annotation.
Internal Configuration with its own authentication provider and url pattern.
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#Order(1)
public static class InternalSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/internal/**")
.authorizeRequests().anyRequest().hasRole("ADMIN")
.and().httpBasic().authenticationEntryPoint(authenticationEntryPoint());
}
}
#Configuration
#Order(2)
public static class ExternalSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/external/**")
.authorizeRequests().anyRequest().hasRole("ADMIN")
.and().httpBasic().authenticationEntryPoint(authenticationEntryPoint());
}
}
Get more detail through using below article.
https://www.baeldung.com/spring-security-multiple-entry-points

How to set two or more AuthenticationProvider in spring security? [duplicate]

There are several references of multiple authentication providers in spring security, but no example in Java config could be located.
The following link gives the XML notation:
Multiple Authentication Providers in Spring Security
We need to authenticate using LDAP or DB
Below is our sample code:
#Configuration
#EnableWebSecurity
public class XSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private AuthenticationProvider authenticationProviderDB;
#Override
#Order(1)
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Order(2)
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProviderDB);
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
}
______
#Override
#Order(1)
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/","/logout","/time").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index")
.loginProcessingUrl("/perform_login")
.usernameParameter("email")
.passwordParameter("password")
.failureUrl("/index?failed=true")
.defaultSuccessUrl("/summary",true)
.permitAll()
.and()
.logout().logoutUrl("/logout")
.logoutSuccessUrl("/index?logout=true").permitAll()
.and()
.exceptionHandling().accessDeniedPage("/error403")
.and().authenticationProvider(authenticationProvider);
}
#Order(1)
protected void configureDB(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/","/logout").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index")
.loginProcessingUrl("/perform_login")
.usernameParameter("email")
.passwordParameter("password")
.failureUrl("/index?failed=true")
.defaultSuccessUrl("/summary",true)
.permitAll()
.authenticationProvider(authenticationProviderDB)
//This line giving compilation error stating authenticationProvider is not available in formloginconfigurer
.and()
.logout().logoutUrl("/logout")
.logoutSuccessUrl("/index?logout=true").permitAll()
.and()
.exceptionHandling().accessDeniedPage("/error403");
}
}
May be this will help you :-
#Configuration
#EnableWebSecurity
#Profile("container")
public class XSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
private AuthenticationProvider authenticationProviderDB;
#Override
#Order(1)
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Order(2)
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProviderDB);
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/rest/**").authenticated()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(new AuthenticationSuccessHandler() {
#Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication a) throws IOException, ServletException {
//To change body of generated methods,
response.setStatus(HttpServletResponse.SC_OK);
}
})
.failureHandler(new AuthenticationFailureHandler() {
#Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException ae) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
})
.loginProcessingUrl("/access/login")
.and()
.logout()
.logoutUrl("/access/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
#Override
public void onLogoutSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication a) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
})
.invalidateHttpSession(true)
.and()
.exceptionHandling()
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and()
.csrf()//Disabled CSRF protection
.disable();
}
}
In Spring Boot this worked for me:
Each Authentication provider is tested in order. If one passes, then its following Authentication providers are skipped
auth.userDetailsService(userDetailsService)...
then:
auth.ldapAuthentication()....
#EnableRedisHttpSession
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService userDetailsService;
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
//each Authentication provider is tested in order
//if one passes then its following Authentication providers are skipped
//DataBase Authentication
auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
LdapContextSource ldapContextSource = new LdapContextSource();
ldapContextSource.setUrl("ldap://192.168.XXX.XXX:389");
ldapContextSource.setBase("dc=companyname,dc=com");
ldapContextSource.setUserDn("cn=user,cn=testgroup,ou=Test,dc=companyname,dc=com");
ldapContextSource.setPassword("user1234");
ldapContextSource.afterPropertiesSet();
//LDAP Authentication
auth.ldapAuthentication()
//The {0} in the (uid={0}) will be replaced by the username entered in the form.
.userSearchBase("ou=Group")
.userSearchFilter("uid={0}")
//.userDnPatterns("uid={0},ou=people")//does the same thing
//Specifies where the search for Roles start
//.groupSearchBase("ou=mathematicians")
//in groups we search for member
//.groupSearchFilter("member={0}")
//.contextSource().ldif("classpath:test-server.ldif");
.contextSource(ldapContextSource);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/hello").access("hasRole('ROLE_ADMIN')")
.antMatchers("/index").fullyAuthenticated()
.antMatchers("/").fullyAuthenticated()
.antMatchers("/home").fullyAuthenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.usernameParameter("username").passwordParameter("password")
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.csrf()
.disable();
}
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordencoder() {
return new BCryptPasswordEncoder();
}
}
This is a successful configuration which helps configure multiple authentication providers in java config.
Thanks a lot ojus for your inputs. It did help in nailing down the issue.
The key is to have
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
auth.authenticationProvider(authenticationProviderDB);
}
Full code below
#Configuration
#EnableWebSecurity
public class XSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private LDAPAuthenticationProvider authenticationProvider;
#Autowired
private DBAuthenticationProvider authenticationProviderDB;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/scripts/**","/styles/**","/images/**","/error/**");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
auth.authenticationProvider(authenticationProviderDB);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/","/logout").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/index")
.loginProcessingUrl("/perform_login")
.usernameParameter("user")
.passwordParameter("password")
.failureUrl("/index?failed=true")
.defaultSuccessUrl("/test",true)
.permitAll()
.and()
.logout().logoutUrl("/logout")
.logoutSuccessUrl("/index?logout=true").permitAll()
.and()
.exceptionHandling().accessDeniedPage("/error");
}
}

Spring Security HTTP Basic for RESTFul and FormLogin (Cookies) for web - Annotations

In Specific
I want to have HTTP Basic authentication ONLY for a specific URL pattern.
In Detail
I'm creating an API interface for my application and that needs to be authenticated by simple HTTP basic authentication. But other web pages should not be using HTTP basic but rather a the normal form login.
Current Configuration - NOT Working
#Override
protected void configure(HttpSecurity http) throws Exception {
http //HTTP Security
.csrf().disable() //Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.antMatchers("/connect/**").permitAll()
.antMatchers("/", "/register").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/api/**").hasRole("API")
.anyRequest().authenticated()
.and() //HTTP basic Authentication only for API
.antMatcher("/api/**").httpBasic()
.and() //Login Form configuration for all others
.formLogin().loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
Waited for 2 days and didn't get any help here. But my research provided me a solution :)
Solution
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private AuthenticationProvider authenticationProvider;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasAnyRole("ADMIN", "API")
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //HTTP with Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.antMatchers("/connect/**").permitAll()
.antMatchers("/", "/register").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and() //Login Form configuration for all others
.formLogin()
.loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
}
}
I dunno if it can be helpful but I couldn't implement the above solution. I found a workaround defining a single Security
#Configuration class
extending
WebSecurityConfigurerAdapter
with both httpBasic() and formLogin() configured. Then I created a custom
CustomAuthEntryPoint implements AuthenticationEntryPoint
that has this logic in the commence method:
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException
{
String urlContext = UtilityClass.extractUrlContext(request);
if (!urlContext.equals(API_URL_PREFIX))
{
String redirectUrl = "urlOfFormLogin"
response.sendRedirect(request.getContextPath() + redirectUrl);
}
else
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
Dunno which is the "best practice strategy" about this issue

Categories