Spring Security Basic Authentication only happens once - java

Recently I am using Spring Security basic authentication for my REST services.
Below is the security xml configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http pattern="/rest/**" create-session="never" use-expressions="true">
<security:http-basic />
<security:intercept-url pattern="/rest/auth/**" access="isAuthenticated()"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder hash="sha-256" />
</security:authentication-provider>
</security:authentication-manager>
<security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled"/>
</beans>
Spring framework and Spring Security that I use:
<springframework.version>4.1.0.RELEASE</springframework.version>
<spring.security.version>3.2.5.RELEASE</spring.security.version>
I map my REST services to URL prefixed with "rest/" and when I access the URL for the first time, the browser prompt the username and password field of basic authentication. I fill it with the right credential and my controller accessed successfully.
However if I try to access the same URL with browser again, it will not prompt me the username and password field of basic authentication again and directly access the URL.
I expect that browser always prompt me with basic authentication because I set create-session attribute to never.
So, am I missing something?

Browser caches credentials. Sometimes clearing the cache doesn't help. The only reliable way how to fake it is use Chrome's incognito window (Ctrl+N). But one prompt per one incognito window. So you need new incognito window when you want to enter them again.
This is the only way I found to test basic authentication manually.

From the javadoc for create-session. I think your application is creating a sessions and that session is being used.
Attribute : create-session Controls the eagerness with which an HTTP
session is created by Spring Security classes. If not set, defaults
to "ifRequired". If "stateless" is used, this implies that the
application guarantees that it will not create a session. This
differs from the use of "never" which mans that Spring Security will
not create a session, but will make use of one if the application
does.
Data Type : string Enumerated Values :
- ifRequired
- always
- never
- stateless
You should try using
"stateless"
instead of
never

Related

How to perform in-browser web app client certificate based authentication without an applet or external app? [duplicate]

This question already has answers here:
Read out incoming certificate in Tomcat
(2 answers)
Closed 7 years ago.
Since google killed the NPAPI plugin and we cannot load applets in Chrome our client certificate based web app authentication scheme is not working anymore.
While looking for alternatives I found out that, because we are using SSL on our private content, there is a way to automatically ask for an SSL client certificate, by enabling SSL client authentication on the web server (In this case Tomcat).
My question is: Once I've enabled Tomcat's SSL client authentication to request this certificate from the client browser's personal certificate store:
How can I obtain the certificate info on my JSF web application so I can register a user with that info on first login and associate it with a user id?
(I am assuming that I don't need to worry about fake or expired certificates since a properly configured Tomcat will reject them, so I don't need to bother with the authentication / certificate validation, but just retrieve the info: Tomcat handles rejections / authentication errors by redirecting to the source page with an error code)
I am going to describe a procedure to validate against spanish DNIe which uses client certificate using JSF 2.2 and Spring Security 4.0, although it is possible to authenticate without using Spring Security.
You said you have enabled Tomcat's SSL client authentication, so I guess it implies you have already configured keyStore with ROOT certificate. If you don't I can provide you with valid instructions for Tomcat 7.
So, once Tomcat is properly configured to require client certificate, and once the handshake has finished, this is what you have to do in your application to read client certificate:
Configure dependencies in pom.xml
Add following dependencies to pom.xml:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.0.1.RELEASE</version>
</dependency>
It is worth to say that Spring Security 4.0.1 is bound to Spring 4.1.X
Configure web.xml to delegate in Spring Security
Tell servlet container, security is delegated into Spring Security
<security-constraint>
<web-resource-collection>
<web-resource-name>Secured</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
It must ask for a client certificate:
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>certificate</realm-name>
</login-config>
Configure Spring Security filter
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>*.jsf</url-pattern>
</filter-mapping>
Don't forget to add spring security file descriptor into contextConfigLocation context param.
Configure Spring Security
Following is a large file which configure Spring Security to validate against client-certificate.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="userDetailsService" class="your.own.UserDetailService">
<property name="dao" ref="userDao" />
</bean>
<bean id="dniPrincipalExtractor" class="your.own.DniePrincipalExtractor">
</bean>
<bean id="x509Filter" class="org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter">
<property name="authenticationManager" ref="authManager" />
<property name="principalExtractor" ref="dniPrincipalExtractor" />
</bean>
<bean id="preauthAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService" ref="authenticationUserDetailsService" />
</bean>
<bean id="authenticationUserDetailsService"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<sec:http pattern="/css/**" security="none" />
<sec:http pattern="/error/**" security="none" />
<sec:http pattern="/icons/**" security="none" />
<sec:http pattern="/imgs/**" security="none" />
<sec:http
auto-config="true"
use-expressions="true"
entry-point-ref="forbiddenAuthEP">
<sec:intercept-url pattern="/*" access="permitAll" />
<sec:intercept-url pattern="/xhtml/**" access="hasRole('ROLE_BASIC')" />
<sec:custom-filter ref="x509Filter" position="X509_FILTER"/>
</sec:http>
<sec:authentication-manager alias="authManager">
<sec:authentication-provider ref="preauthAuthenticationProvider" />
</sec:authentication-manager>
</beans>
This file creates a security context that requires login by means of a x509Filter. This filter needs a
dniPrincipalExtractor which a class you need to find and extract dni from user certificate.
userDetailsService which knows how to find the user into data base, using userDao.
With this configuration, once a client certificate is received, a pre-authentication service acts to extract DNI and load user from data base (or whatever) building the
This code implies you have to build three classes of your own:
your.own.UserDao
your.own.UserDetailService it has to implements org.springframework.security.core.userdetails.UserDetailsService. Here you have to retrieve roles or groups assigned to user to build List<GrantedAuthority> for the user and create a valid org.springframework.security.core.userdetails.User.
your.own.DniePrincipalExtractor it has to implements org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor
Sample UserDetailService
package your.own.package;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import your.own.UserDAO;
public class UserDetailService implements UserDetailsService {
private UserDAO dao = null;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String error = null;
UserDetails result = null;
if(StringUtils.isNotEmpty(username)){
if(dao.findById(username) != null){
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_BASIC", "ROLE_ADMIN");
result = new org.springframework.security.core.userdetails.User(username, "", authorities);
}
}else{
error = "No se ha especificado login para el usuario.";
}
if(result == null){
if(StringUtils.isEmpty(error)){
error = String.format("No se encuentra ningĂșn usuario con login %s", username);
}
throw new UsernameNotFoundException(error);
}
return result;
}
}
For simplicity I put roles by hand, obviously you will have to change this.
Get authenticated user
Now you can get authenticated user this way, in session bean or whatever
SecurityContextHolder.getContext().getAuthentication().getName()
If you need, I can provide you with more information, but I didn't want to write a very large answer. Things that have been not covered in this answer:
DNI principal extractor: If you search google you will find several implementations, but I can provide you one.
OCSP validation: You have to manage cert validation against Policia Nacional OCSP server. I can tell you how to do.
JSF Tag Libs to ask for user grants.
Tomcat full configuration.
Implementing a fallback mechanism to launch a form validation page if there is no client certificate. It is possible with Spring Security
My first implementation didn't use Spring Security, but as far I was concern with the need to provide a fallback mechanism, I move forward Spring Security, although I didn't show you how to do here, for simplicity.
Hope it helps!

Spring security access with multiple roles

I want to define access for some pages for user who has one of following roles (ROLE1 or ROLE2)
I'm trying to configure this in my spring security xml file as following:
<security:http entry-point-ref="restAuthenticationEntryPoint" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security" use-expressions="true">
<!-- skipped configuration -->
<security:intercept-url pattern="/rest/api/myUrl*" access="hasRole('ROLE1') or hasRole('ROLE2')" />
<!-- skipped configuration -->
</security:http>
I've tried various ways like:
access="hasRole('ROLE1, ROLE2')"
access="hasRole('ROLE1', 'ROLE2')"
access="hasAnyRole('[ROLE1', 'ROLE2]')"
etc
but nothing seems to be working.
I'm keep getting exception
java.lang.IllegalArgumentException: Unsupported configuration attributes:
or
java.lang.IllegalArgumentException: Failed to parse expression 'hasAnyRole(['ROLE1', 'ROLE2'])'
how should it be configured?
Thanks
How try with , separate. See doc here and here.
<security:intercept-url pattern="/rest/api/myUrl*" access="ROLE1,ROLE2"/>
OR
hasAnyRole('ROLE1','ROLE2')
The problem was that I configured custom access-decision-manager-ref="accessDecisionManager"
and didn't pass one of the voters.
Solved by adding org.springframework.security.web.access.expression.WebExpressionVoter to accessDecisionManager bean.

enable security check to access wsdl url

I have created a web service in my machine. Its URL is
http://localhost:8080/aaa/test?wsdl
I want to enable one feature to it. As soon as the user enters the url in browser, it should ask for the credentials. Can it be done in web services.
If yes, can some one guide how to achieve it.
Thanks.
If you're already using Spring, you can easily apply basic authentication to a specific URL pattern with Spring Security. In your applicationContext.xml, just add:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<!-- HTTP basic authentication in Spring Security -->
<http>
<intercept-url pattern="/*wsdl?" access="ROLE_USER" />
<http-basic />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="someUser" password="somePassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Example taken from Mkyong's Spring Security HTTP Basic Authentication Example.
If you'd like to lookup users in a database, you'd need to use a different authentication provider. The Spring Security reference mentions data-source-ref if you'd like to query the standard Spring Security user data tables. If you've already got your own structure, you might be interested in using user-service-ref instead, in which you can lookup the users yourself.
<authentication-manager>
<authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>
<beans:bean id="myUserDetailsService"
class="mypackage.MyUserDetailsService">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
And code mypackage.MyUserDetailsService extending JdbcDaoImpl and implementing UserDetailsService.

Implementing A Controller for Authorization

I use Spring and Spring Security 3 at my application. All my clients side are static HTML files. I have a navigation bar that includes buttons like:
List
Edit
Delete
Update
When a user clicks any of them another page loads at bottom. Users have roles at my application. Some users do not have edit and delete authorization, while others do. That buttons should be visible to users which have the authorization. If a user doesn't have edit the correct permission he/she must not see the edit button. I have the buttons defined in an HTML file: navigation.html. I figured out that: there will be many navigation.html files. One of them includes all buttons(for admin) one of them just includes list button. If a user requests that navigation.html I want to send the correct one. So I can have that ability:
<logout logout-url="/j_spring_security_logout" logout-success-url="/login.html"/>
similar to that user will request that file from an URL(as like /navigation). There will be a controller to handle it so will return any of that navigation files.
Does that design sound correct? If so, how can I implement that? Any other simple solutions are welcome I am new to Spring and Spring Security.
For general Spring Security use, you don't need to write your own code to enable authorization. I generally configure Spring Security in XML to control access at a gross level to various resources based on Roles. Then, I annotate the controllers and/or handler methods to restrict more precisely.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns:security="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<security:global-method-security secured-annotations="enabled">
</security:global-method-security>
<security:http auto-config="true" disable-url-rewriting="true">
<security:intercept-url pattern="/*.do" access="ROLE_USER" />
<security:intercept-url pattern="/index.jsp" access="ROLE_USER" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/login.jsp" filters="none" />
<security:form-login login-page="/login.jsp" />
<security:logout />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:password-encoder hash="md5" />
<security:jdbc-user-service data-source-ref="my-ds"/>
</security:authentication-provider>
</security:authentication-manager>
</beans:beans>
And then in the Controller:
#Secured({"ROLE_SPECIAL_USER"})
#RequestMapping("/somespecial.do")
Within a JSP:
<%# taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<authz:authorize ifAnyGranted="ROLE_SPECIAL_USER">
...some special JSP code...
</authz:authorize>
Based on your using static HTML, I would think that the design you specify would be reasonable.
Have a Controller that maps to navigation.html, and it would simply look at the granted authorities of the current user and return the correct static html view name for the html file that has all (and only) the appropriate controls.

How to edit timed logout in Spring security

I am trying to figure out where the timed-logout function of Spring's light security is located, and how to edit it to use my custom logout method.
My understanding is that there does exist an editable timed-logout function, I have just thus far been unable to find it, and when/if I do, I am unsure how to make it use my logout sequence.
Thanks,
MirroredFate
EDIT FOR CLARITY:
It is a web/servlet application. I am using acegi security.
I am using the Spring session timeout right now:
In web.xml:
<session-config>
<session-timeout>5</session-timeout>
</session-config>
I need a way to execute some code when this timeout occurs. However, I have NO idea how to do this.
If I am unable to execute code using this method, my understanding is that acegi has a way to make a session timeout; however, I have no idea how to do that either. I already have the ability to execute the code on a normal logout using acegi:
<security:logout invalidate-session="true"
success-handler-ref="Logout"
logout-url="/logout.html" />
</security:http>
So, essentially, how do I do this same thing either with an acegi timed logout or when a session timeout occurs?
The HttpSessionListener might be what you are looking for. The problem with depending on Spring's session management is that if a user simply closes his browser without logging out, the invalid-session-url will never be reached (because they never make another request).
Something like this:
public class MySessionListner implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent se) {
return; //or maybe do something, depends on what you need
}
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
//do whatever you need to do
}
}
Then in web.xml:
<listener>
<listener-class>com.foo.MySessionListener</listener-class>
</listener>
That way your code will be called every time a session is destroyed, not just when a user tries to access a page after timing out. Hope that helps.
The session timeout period is managed by your application server (just as you have it now in the web.xml). The handling for what happens when the session timeout occurs can be specified in Spring. For instance, Spring 3.0 can specify what page to redirect the user to when they make a request after their session has been invalidated. See below.
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="http://www.springframework.org/schema/security"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<sec:http auto-config="true" access-denied-page="/login">
<sec:session-management invalid-session-url="/session-timeout" />
<sec:anonymous enabled="true" />
<sec:intercept-url ... />
<sec:form-login ... />
<sec:logout invalidate-session="true" logout-success-url="/login" />
</sec:http>
<!-- Other bean declarations -->
</b:beans>

Categories

Resources