A Spring Bean methods in an application I'm working on are being called in two ways:
through AngularJS and
Spring MVC controller(Form login) or by using SOAP(Basic Authentication).
To allow this I have setup the following configuration for the CXF servlet:
#Configuration
public class CxfConfiguration {
#Autowired
private ApplicationContext applicationContext;
#Bean
public ServletRegistrationBean dispatcherServletSOAP() {
return new ServletRegistrationBean(new CXFServlet(), "/soap/*");
}
#Bean(name= Bus.DEFAULT_BUS_ID)
public SpringBus springBus() {
return new SpringBus();
}
#Bean
public Endpoint documentEndpoint(){
Bus bus = (Bus) applicationContext.getBean(Bus.DEFAULT_BUS_ID);
DocumentService implementor = new DocumentServiceImpl();
EndpointImpl endpoint = new EndpointImpl(bus, implementor);
endpoint.publish("/document");
return endpoint;
}
and security configuration:
#Configuration
#Order(1)
public static class SOAPSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.httpBasic()
.and()
.antMatcher("/soap/**")
.authorizeRequests()
.anyRequest()
.hasRole("USER");
}
}
#Configuration
#Order(2)
public static class HTTPSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/soap/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
I realize that this isn't a very good configuration as there are several cases in which from the browser or SOAP UI, things don't work as expected.
My questions would be: what would be a good way to implement security based on these requirements and am I on the right track with this configuration?
Also, I'm using Spring Boot 1.3.2 and Apache CXF 3.1.4
I finally ended up with this configuration that works:
#Configuration
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#Order(1)
public static class SOAPWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().ignoringAntMatchers("/soap/**")
.and()
.antMatcher("/soap/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().requestCache().disable();
}
}
#Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
}
You should try this, may be it will help you:
#Configuration
#EnableWebSecurity
#Profile("container")
public class SOAPSecurityConfig 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();
}
}
Related
I decided to add some css to my application but it isn't working because of spring security. Here is what i tried to fix this.
1)adding to the mvcConfig
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
2)added this to webSecurityConfig
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
3)also i have this method
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/","/registration","/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
also i added this to application.properties file:
spring.mvc.static-path-pattern=/resources/**
none of this methods are working for me. if anyone dealt with this, please help
you can check out the whole project if it helps my project
p.s. i'm just a beginner in spring, so dont judge me
You have to ignore the css directory too.
#Component
public class SecurityConfig implements WebSecurityConfigurer {
#Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/css/**")
.antMatchers("/js/**")
.antMatchers("/images/**")
.antMatchers("/resources/**");
}
}
Authentication and Authorization is working fine. But after successful login it not redirecting me to client side further it open source code of some .js file. While previous (without custom login form loginPage("/login")) it successfully redirecting me to last page clicked (client side) which called for authenticate.
My Server side code as below:
Authorization server
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("ClientId")
.secret("secret")
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.redirectUris("http://localhost:8082/ui/login")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
Resource Server
#Configuration
#EnableResourceServer
public class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/api/**").and().authorizeRequests()
.antMatchers("/api/**").authenticated().and()
.antMatcher("/rest/hello/principal")
.authorizeRequests().anyRequest().authenticated();
}
My Security Config
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/oauth/token/revokeById/**").permitAll()
.antMatchers("/tokens/**").permitAll().anyRequest().authenticated().and()
.formLogin().loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.failureUrl("/login?error")
.defaultSuccessUrl("/").permitAll().and()
.csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordencoder());
}
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordencoder() {
return new CustomPasswordEncoder();
}
}
you need to create
SimpleUrlAuthenticationSuccessHandler implementation
public class RefererRedirectionAuthenticationSuccessHandler
extends SimpleUrlAuthenticationSuccessHandler
implements AuthenticationSuccessHandler {
public RefererRedirectionAuthenticationSuccessHandler() {
super();
setUseReferer(true);
}
}
and add one line to the WebSecurityConfiguration
.successHandler(new RefererRedirectionAuthenticationSuccessHandler())
And after that you method will look like as shown below
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login").permitAll().antMatchers("/oauth/token/revokeById/**").permitAll()
.antMatchers("/tokens/**").permitAll().anyRequest().authenticated().and()
.formLogin().loginPage("/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(new RefererRedirectionAuthenticationSuccessHandler())
.failureUrl("/login?error")
.defaultSuccessUrl("/").permitAll().and()
.csrf().disable();
}
I am trying to create a REST Api with Spring-Boot and I need to disable security for testing purposes. I want to be able to use PostMan without any security constrain.
I have tried several ways but nothing seems to work it's as if the AplicationTest configurations are never applied.
This is the code for my ApplicationTest class
#SpringBootApplication
#Configuration()
public class ApplicationTests {
public static void main(String[] args) {
SpringApplicationBuilder ab = new SpringApplicationBuilder(ApplicationTests.class);
Map<String, Object> properties = new HashMap<>();
properties.put("server.port", 9999);
properties.put("security.basic.enabled", false);
properties.put("security.enable-csrf", false);
ab.properties(properties);
ab.run(args);
}
#Configuration
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable();
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
}
This is my SecurityConfig class
#Configuration
#ComponentScan("com.app")
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
AuthenticationService authenticationService;
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/api/business/**").hasAnyRole("BUSINESS", "ADMIN")
.antMatchers("/api/users/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/api/admins/**").hasRole("ADMIN")
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// #formatter:on
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
ShaPasswordEncoder encoder = new ShaPasswordEncoder();
auth.userDetailsService(authenticationService).passwordEncoder(encoder);
}
}
Here is the error log.
org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:962)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:324)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:281)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:111)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4656)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5309)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Here are my configuration classes.
Spring version= 4.1.6.RELEASE
Spring security version= 4.1.0.RELEASE
1)WebInitializer implementing WebMvcConfigurerAdapter
public class WebInitializer implements WebApplicationInitializer
{
#Override
public void onStartup( ServletContext container )
{
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register( AppConfig.class );
rootContext.setServletContext( container );
container.addListener( new ContextLoaderListener( rootContext ) );
container.addFilter("CORSFilter", it.codegen.tbx.central.service.config.SimpleCORSFilter.class)
.addMappingForUrlPatterns(null, false, "");
ServletRegistration.Dynamic dispatcher = container.addServlet( "dispatcher",
new DispatcherServlet( rootContext ) );
dispatcher.addMapping( "/" );
dispatcher.setLoadOnStartup( 1 );
}
}
2)AppConfig extending WebMvcConfigurerAdapter
#Configuration
#EnableWebMvc
#ComponentScan({ "it.codegen.tbx.central.service.config","it.codegen.tbx.central.service.backend.cache", "it.codegen.tbx.central.admin.config", "it.codegen.tbx.central.admin.service.controller", "it.codegen.tbx.central.admin.service.backend.tbx"})
#Import({ SecurityConfig.class })
public class AppConfig extends WebMvcConfigurerAdapter
{
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
3)SecurityConfig extending WebSecurityConfigurerAdapter
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("abc");
auth.inMemoryAuthentication().withUser("chaya").password("chaya").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/booking/search").access("hasAuthority('USER')")
.antMatchers("/booking/delete").access("hasAuthority('ADMIN')")
.and()
.formLogin()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
}
4)AbstractSecurityWebApplicationInitializer
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
I have gone through similar questions here and none of the solutions worked.
You have to annotate your Java configuration (SecurityConfig) with #EnableWebSecurity to add springSecurityFilterChain to your application context.
Your modified code:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("abc");
auth.inMemoryAuthentication().withUser("chaya").password("chaya").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/booking/search").access("hasAuthority('USER')")
.antMatchers("/booking/delete").access("hasAuthority('ADMIN')")
.and()
.formLogin()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
}
I have an inMemoryAuthentication configuration that works:
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(
AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
authenticationManagerBuilder //
.inMemoryAuthentication() //
.withUser("employee") //
.password("employee") //
.roles("RoleEmployee")
;
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
httpSecurity
.authorizeRequests()
.antMatchers("/login","/login.request","/logout").permitAll()
.anyRequest().hasRole("RoleEmployee")
.and()
.formLogin()
.loginPage("/login.request")
.loginProcessingUrl("/login")
.failureUrl("/login.request?error")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll()
.logoutSuccessUrl("/login.request")
;
// #formatter:on
}
}
I want to now use Siteminder authentication and changed this to:
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private PreAuthenticatedAuthenticationProvider preAuthenticatedProvider;
public WebSecurityConfiguration() {
super();
userDetailsService = new CustomUserDetailsService();
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper = new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(
userDetailsService);
preAuthenticatedProvider = new PreAuthenticatedAuthenticationProvider();
preAuthenticatedProvider.setPreAuthenticatedUserDetailsService(wrapper);
}
#Override
protected void configure(
AuthenticationManagerBuilder authenticationManagerBuilder)
throws Exception {
// #formatter:off
authenticationManagerBuilder //
.authenticationProvider(preAuthenticatedProvider);
// #formatter:on
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// #formatter:off
RequestHeaderAuthenticationFilter siteMinderFilter = new RequestHeaderAuthenticationFilter();
siteMinderFilter.setAuthenticationManager(authenticationManager());
httpSecurity
.addFilter(siteMinderFilter)
.authorizeRequests()
.antMatchers("/login","/login.request","/logout").permitAll()
.anyRequest().hasRole("RoleEmployee")
.and()
.formLogin()
.loginPage("/login.request")
.loginProcessingUrl("/login")
.failureUrl("/login.request?error")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll()
.logoutSuccessUrl("/login.request")
;
// #formatter:on
}
}
For now CustomUserDetailsService always returns a user with the employee role:
public class CustomUserDetailsService implements
UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("RoleEmployee");
authorities.add(authority);
UserDetails user = new User(username, "password", authorities);
return user;
}
}
When I test this, the SM_USER header is correctly passed in and I can see in the debugger that CustomUserDetailsSerice is correctly called, but a 403 Forbidden status is returned for any page that I was previously able to access successfully under the old configuration.
Is there something wrong with this configuration?
Oftentimes asking the question helps answer it.
Changing:
anyRequest().hasRole("RoleEmployee")
to:
anyRequest().hasAuthority("RoleEmployee")
fixed it.