http://docs.spring.io/spring-security/site/docs/4.1.x/guides/html5/hellomvc-javaconfig.html
http://stackoverflow.com/questions/24122586/how-to-represent-the-spring-security-custom-filter-using-java-configuration
http://stackoverflow.com/questions/15946132/springsecurity-fail-to-delete-jsessionid
.addLogoutHandler(new ProperCookieClearingLogoutHandler("JSESSIONID","USER"))
https://java.net/jira/browse/JERSEY-2919
http://stackoverflow.com/questions/21586070/spring-security-preauthorize-breaks-jersey-context-uriinfo-injection
Actually a workaround seems to be to inject the @Context UriInfo uriInfo into the resource method instead of at the class level.
http://stackoverflow.com/questions/33541678/preauthorizepermitall-still-requires-authentication
http://websystique.com/spring-security/spring-security-4-method-security-using-preauthorize-postauthorize-secured-el/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
Filtering using
http://stackoverflow.com/questions/27390363/spring-how-to-inject-an-inline-list-of-strings-using-value-annotation
The spring convertion service will perform the split for you if your reference is an
http://stackoverflow.com/questions/16113115/how-do-i-use-a-custom-authorities-populator-with-spring-security-and-the-actived
http://forum.spring.io/forum/spring-projects/security/101786-spring-security-how-to-add-remove-authorities-of-the-user-after-he-logs-in
The easiest option is to obtain the current Authentication and create a new instance of it and set it on the SecurityContextHolder as described in Setting the SecurityContextHolder Contents Directly. Be sure you understand the implications of acting upon the Authentication in multiple threads (read on in the reference to understand). An example of adding a GrantedAuthority to the current Authentication is given below:
https://spapas.github.io/2013/10/14/spring-ldap-custom-authorities/
http://stackoverflow.com/questions/25398301/manually-authenticate-use-spring-security
http://stackoverflow.com/questions/22845474/spring-security-3-2-1-multiple-login-forms-with-distinct-websecurityconfigurerad
http://stackoverflow.com/questions/25794680/multiple-authentication-mechanisms-in-a-single-app-using-java-config
http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html
Get current logged in username in Spring Security
public class MessageSecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
The
MessageSecurityWebApplicationInitializer
will automatically register the springSecurityFilterChain Filter for every URL in your application. If Filters are added within other WebApplicationInitializer
instances we can use@Order
to control the ordering of the Filter instances.- Your filter needs to be added before the standard
UsernamePasswordAuthenticationFilter
http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
- If you extend UsernamePasswordAuthenticationFilter your filter will return immediately without doing anything unless you set a
RequestMatcher
myAuthFilter.setRequiresAuthenticationRequestMatcher( new AntPathRequestMatcher("/login","POST"));
- All the configuration you do in
http.formLogin().x().y().z()
is applied to the standardUsernamePasswordAuthenticationFilter
not the custom filter you build. You will need to configure it manually yourself. My auth filter initialization looks like this:@Bean public MyAuthenticationFilter authenticationFilter() { MyAuthenticationFilter authFilter = new MyAuthenticationFilter(); authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST")); authFilter.setAuthenticationManager(authenticationManager); authFilter.setAuthenticationSuccessHandler(new MySuccessHandler("/app")); authFilter.setAuthenticationFailureHandler(new MyFailureHandler("/login?error=1")); authFilter.setUsernameParameter("username"); authFilter.setPasswordParameter("password"); return authFilter; }
Before executing the Authentication process, Spring Security will run a filter responsible with storing the Security Context between requests – the SecurityContextPersistenceFilter. The context will be stored according to a strategy – HttpSessionSecurityContextRepository by default – which uses the HTTP Session as storage.
For the strict create-session=”stateless” attribute, this strategy will be replaced with another –NullSecurityContextRepository – and no session will be created or used to keep the context.
4. Concurrent Session Control
When a user that is already authenticated tries to authenticate again, the application can deal with that event in one of a few ways. It can either invalidate the active session of the user and authenticate the user again with a new session, or allow both sessions to exist concurrently.
http.sessionManagement().maximumSessions(
2
)
http.sessionManagement()
.expiredUrl(
"/sessionExpired.html"
)
.invalidSessionUrl(
"/invalidSession.html"
);
Exposing session information in the URL is a growing security risk (from place 7 in 2007 to place 2 in 2013 on the OWASP Top 10 List).
Starting with Spring 3.0, the URL rewriting logic that would append the jsessionid to the URL can now be disabled by setting the disable-url-rewriting=”true” in the <http> namespace.
Alternatively, starting with Servlet 3.0, the session tracking mechanism can also be configured in the web.xml:
1
2
3
| < session-config > < tracking-mode >COOKIE</ tracking-mode > </ session-config > |
And programmatically:
1
| servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE)); |
This chooses where to store the JSESSIONID – in the cookie or in a URL parameter.
http.sessionManagement() .sessionFixation().migrateSession() |
By default, Spring Security has this protection enabled (“migrateSession“) – on authentication a new HTTP Session is created, the old one is invalidated and the attributes from the old session are copied over.
If this is not the desired behaviour, two other options are available:
- when “none” is set, the original session will not be invalidated
- when “newSession” is set, a clean session will be created without any of the attributes from the old session being copied over
http://stackoverflow.com/questions/15946132/springsecurity-fail-to-delete-jsessionid
.addLogoutHandler(new ProperCookieClearingLogoutHandler("JSESSIONID","USER"))
The default CookieClearingLogoutHandler provided by spring could not clear JSESSIONID due to a difference in cookie path.
You should not change the path of cookie. This would change the cookie identity. If the cookie were set for a path like /foo and you change this to /, then the client won't associate the changed cookie with the original cookie anymore. A cookie is identified by the name and the path.
Therefore you need to implement a custom CookieClearingLogoutHandler as shown in the above solution i.e (ProperCookieClearingLogoutHandler.class) and set it to spring security as shown in below code .Instead of using .deleteCookies("JSESSIONID","USER") which adds CookieClearingLogoutHandler by default.
public final class ProperCookieClearingLogoutHandler implements LogoutHandler {
private final List<String> cookiesToClear;
public ProperCookieClearingLogoutHandler(String... cookiesToClear) {
Assert.notNull(cookiesToClear, "List of cookies cannot be null");
this.cookiesToClear = Arrays.asList(cookiesToClear);
}
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
for (String cookieName : cookiesToClear) {
Cookie cookie = new Cookie(cookieName, null);
String cookiePath = request.getContextPath() + "/";
if (!StringUtils.hasLength(cookiePath)) {
cookiePath = "/";
}
cookie.setPath(cookiePath);
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
}
http://stackoverflow.com/questions/21586070/spring-security-preauthorize-breaks-jersey-context-uriinfo-injection
Actually a workaround seems to be to inject the @Context UriInfo uriInfo into the resource method instead of at the class level.
http://stackoverflow.com/questions/33541678/preauthorizepermitall-still-requires-authentication
Method security is applied after the web security filter.
Since you have
anyRequest().fullyAuthenticated()
in your configuration, your findAll
method will never be hit. anyRequest().fullyAuthenticated()
means that all attempts to access a web endpoint that does no have have some from of full user authentication on it will fail.
From the JavaDoc
Specify that URLs are allowed by users who have authenticated and were not "remembered".
You will need to add an additional path in your web security, some like.
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.antMatchers(HttpMethod.GET, '/somePath').permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
http://www.baeldung.com/spring-security-logout<
logout
logout-url
=
"/perform_logout"
delete-cookies
=
"JSESSIONID"
success-handler-ref
=
"customLogoutSuccessHandler"
/>
http://websystique.com/spring-security/spring-security-4-method-security-using-preauthorize-postauthorize-secured-el/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
- prePostEnabled :Determines if Spring Security’s pre post annotations [@PreAuthorize,@PostAuthorize,..] should be enabled.
- secureEnabled : Determines if Spring Security’s secured annotation [@Secured] should be enabled.
- jsr250Enabled : Determines if JSR-250 annotations [@RolesAllowed..] should be enabled.
You can enable more than one type of annotation in the same application, but only one type should be used for any interface or class as the behavior will not be well-defined otherwise. If two annotations are found which apply to a particular method, then only one of them will be applied.
@Secured annotation is used to define a list of security configuration attributes for business methods. You can specify the security requirements[roles/permission etc] on a method using @Secured, and than only the user with those roles/permissions can invoke that method. If anyone tries to invoke a method and does not possess the required roles/permissions, an AccessDenied exception will be thrown.
@Secured is coming from previous versions of Spring. It has a limitation that it does not support Spring EL expressions.
Spring’s
@PreAuthorize/@PostAuthorize
annotations are preferred way for applying method-level security, and supports Spring Expression Language out of the box, and provide expression-based access control.
@PreAuthorize is suitable for verifying authorization before entering into method. @PreAuthorize can take into account, the roles/permissions of logged-in User, argument passed to the method etc.
@PostAuthorize , not often used though, checks for authorization after method have been executed, so it is suitable for verifying authorization on returned values. Spring EL provides returnObject object that can be accessed in expression language and reflects the actual object returned from method.
@PostAuthorize
(
"returnObject.type == authentication.name"
)
User findById(
int
id);
@PreAuthorize
(
"hasRole('ADMIN')"
)
void
updateUser(User user);
@PreAuthorize
(
"hasRole('ADMIN') AND hasRole('DBA')"
)
void
deleteUser(
int
id);
Additionally, we have added a method findById() with @PostAuthorize annotation. With @PostAuthorize, the returned value from the method(User object) will be accessible with
returnObject
in Spring Expression Language, and individual properties of return user object can be used to apply some security rules. In this example we are making sure that a logged-in user can only get it’s own User type object.
Filtering using @PreFilter
and @PostFilter
As you may already be aware, Spring Security supports filtering of collections and arrays and this can now be achieved using expressions. This is most commonly performed on the return value of a method. For example:
@PreAuthorize("hasRole('ROLE_USER')") @PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')") public List<Contact> getAll();
When using the
@PostFilter
annotation, Spring Security iterates through the returned collection and removes any elements for which the supplied expression is false. The name filterObject
refers to the current object in the collection. You can also filter before the method call, using @PreFilter
, though this is a less common requirement. The syntax is just the same, but if there is more than one argument which is a collection type then you have to select one by name using thefilterTarget
property of this annotation.
http.authorizeRequests()
.antMatchers(
"/"
,
"/home"
).access(
"hasRole('USER') or hasRole('ADMIN') or hasRole('DBA')"
)
.and().formLogin().loginPage(
"/login"
)
.usernameParameter(
"ssoId"
).passwordParameter(
"password"
)
.and().exceptionHandling().accessDeniedPage(
"/Access_Denied"
);
}
The spring convertion service will perform the split for you if your reference is an
array
or Collection
, so you don't need that ugly expression: just @Value("${list.of.strings}")
http://stackoverflow.com/questions/16113115/how-do-i-use-a-custom-authorities-populator-with-spring-security-and-the-actived
http://forum.spring.io/forum/spring-projects/security/101786-spring-security-how-to-add-remove-authorities-of-the-user-after-he-logs-in
The easiest option is to obtain the current Authentication and create a new instance of it and set it on the SecurityContextHolder as described in Setting the SecurityContextHolder Contents Directly. Be sure you understand the implications of acting upon the Authentication in multiple threads (read on in the reference to understand). An example of adding a GrantedAuthority to the current Authentication is given below:
Code:
// update database with new role //... you fill in this part // update the current Authentication Authentication auth = SecurityContextHolder.getContext().getAuthentication(); List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities()); authorities.add(new GrantedAuthorityImpl('ROLE_NEWROLE')); Authentication newAuth = new UsernamePasswordToken(auth.getPrincipal(),auth.getCredentials(),authorities) SecurityContextHolder.getContext().setAuthentication(newAuth);
https://spapas.github.io/2013/10/14/spring-ldap-custom-authorities/
http://stackoverflow.com/questions/25398301/manually-authenticate-use-spring-security
http://stackoverflow.com/questions/22845474/spring-security-3-2-1-multiple-login-forms-with-distinct-websecurityconfigurerad
The component of the spring login chain that redirects to a login page is the authentication filter, and the filter that get's plugged in when using
http.formLogin()
is DefaultLoginPageGeneratingFilter
.
This filter either redirects to the login url or builds a default basic login page, if no login page url is provided.
What you need then is a custom authentication filter with the logic to define which login page is needed, and then plug it in the spring security chain in place of the single page authentication filter.
http://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user").password("password").roles("USER"); } }
The name of the configureGlobal method is not important. However, it is important to only configure AuthenticationManagerBuilder in a class annotated with either
@EnableWebSecurity , @EnableGlobalMethodSecurity , or @EnableGlobalAuthentication . Doing otherwise has unpredictable results. |
public class SpringWebMvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HelloWebSecurityConfiguration.class };
}
...
}
http://stackoverflow.com/questions/30536938/how-to-implement-spring-security-4-with-both-xml-and-java-config@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("abc").password("123456").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("123456").roles("ADMIN");
auth.inMemoryAuthentication().withUser("dba").password("123456").roles("DBA");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.antMatchers("/dba/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_DBA')")
.and().formLogin();
}
}
http://stackoverflow.com/questions/7413304/favicon-ico-not-found-errorThe issue is, when the browser cache is empty and a user comes in, here is what happens:
- the user requests URL "/". This URL is cached.
- the browser makes a requests to "/favicon.ico". This URL becomes the new URL where to redirect to upon authentication.
- the user posts the login form and is redirected to "/favicon.ico".
To fix this, you need to set "/favicon.ico" as being a non-secured resources:<intercept-url pattern="/favicon.ico" access="ROLE_ANONYMOUS" />
/favicon.ico
is something which every browser tries to get from any site it visits to display a nice icon in the location bar. My first guess is that your application sends a login-form back to the browser instead of the file or a 404 NOT FOUND. Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName(); //get logged in username
Spring security:
@EnableWebSecurity
@Configuration
public class CustomWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth
.inMemoryAuthentication()
.withUser("user") // #1
.password("password")
.roles("USER")
.and()
.withUser("admin") // #2
.password("password")
.roles("ADMIN","USER");
}
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**"); // #3
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.antMatchers("/signup","/about").permitAll() // #4
.antMatchers("/admin/**").hasRole("ADMIN") // #6
.anyRequest().authenticated() // 7
.and()
.formLogin() // #8
.loginUrl("/login") // #9
.permitAll(); // #5
}
}
http://stackoverflow.com/questions/23344787/spring-ldap-security-without-xml
I've modified SecurityConfig.java as follows:
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldap_url);
contextSource.setUrl(ldap_user);
contextSource.setPassword(ldap_password);
DefaultLdapAuthoritiesPopulator ldapAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups");
ldapAuthoritiesPopulator.setGroupRoleAttribute("ou");
LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthenticationProviderConfigurer = auth.ldapAuthentication();
ldapAuthenticationProviderConfigurer
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource(contextSource)
.ldapAuthoritiesPopulator(ldapAuthoritiesPopulator);
}
}
but when I login using the web form, I get this error:
java.lang.NullPointerException
at java.util.Hashtable.<init>(Hashtable.java:296)
at org.springframework.ldap.core.support.AbstractContextSource.getAuthenticatedEnv(AbstractContextSource.java:499)
at org.springframework.ldap.core.support.AbstractContextSource.doGetContext(AbstractContextSource.java:114)
at org.springframework.ldap.core.support.AbstractContextSource.getContext(AbstractContextSource.java:110)
at org.springframework.security.ldap.authentication.BindAuthenticator.bindWithDn(BindAuthenticator.java:112)
You need to call
contextSource.afterPropertiesSet()
if you are using the class outside an application context (see the source and Javadoc for Spring LDAP's AbstractContextSource for more information). Either that or you can just make it an @Bean
and Spring will call the method and initialize it for you.