< ?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"
xmlns:p="http://www.springframework.org/schema/p"
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-3.1.xsd">
< security:global-method-security secured-annotations="enabled" />
< security:http>
< security:intercept-url pattern="/index*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
< security:intercept-url pattern="/login123" access="ROLE_ADMIN" />
< security:intercept-url pattern="/employee1" access="ROLE_EMPLOYEE"/>
< security:intercept-url pattern="/emppreviewshow" access="ROLE_EMPLOYEE"/>
< security:access-denied-handler error-page="/login"/>
<security:form-login login-page="/login" default-target-url="/index"
authentication-failure-url="/fail2login"
username-parameter="username"
password-parameter="j_password" />
<security:session-management invalid-session-url="/logout" session-fixation-protection="newSession" >
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:logout logout-success-url="/logout" delete-cookies="JSESSIONID" invalidate-session="true"/>
</security:http>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" >
<constructor-arg name="strength" value="255" />
</bean>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select username,password, enabled from USER_MASTER where username=?"
authorities-by-username-query=
"select username,USER_ROLE from USER_ROLE where username =? " />
<security:password-encoder ref="passwordEncoder" />
</security:authentication-provider>
</security:authentication-manager>
when i am clicking the logout and when clicking the back button of browser still it is showing the old pages.I want the same login url to be shown when back button is clicked in browser.
you can check the session is active in your all the methods of the controller classes.ie.,request mapped classes,methods.if the session is active then return the page.otherwise redirect to login page.
Welcome to the world of client vs server! Invalidating a session is an on server operation. Assuming that the session id is passed in a cookie, it means that next request containing that cookie will not be member of the previous session, and so you will activate all the "please login first" machinery.
But under normal conditions, hitting the back button on a browser does not send a new request but just display the last page from the local cache. Thus it is a client only operation.
As an application developper, there is little that you can do. You could try to use javascript to hide back button, catch it, or clean the cache. But if I were you, I won't dare to think about that: you are likely to fall in browser compatibiliy problem, for something that you should not care about. What user reads locally is its own problem. If he/she made a printed copy of a page, you would not take a lighter to burn it when the session is over. The cached pages are the same: a local copy. That's the reason why on explicit disconnection you often see a message asking to close the browser window. Itsi the only way for the user to be sure not to read offline copies if he/she click on the back button.
i cannot use the invalidate-session. i just add the "authentication-success-handler-ref" . and set a session inside there.after login the session is set to true.and after logout the sesison is set to false.
this is the code:
Securuty-context.xml
<bean id="customAuthenticationSuccessHandler" class="org.dewbyte.corebank.utility.CustomAuthenticationSuccessHandler"/>
root-context.xml
<bean id="LogoutSuccessHandler" class="org.dewbyte.corebank.utility.LogoutSuccessHandler" />
CustomAuthenticationSuccessHandler class
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
request.getSession().setAttribute("loginStatus", "true");
String targetUrl = "/dashboard";
redirectStrategy.sendRedirect(request, response, targetUrl);
}
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}
LogoutSuccessHandler class
public class LogoutSuccessHandler implements org.springframework.security.web.authentication.logout.LogoutSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public RedirectStrategy getRedirectStrategy() {
return redirectStrategy;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
#Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
request.getSession().setAttribute("loginStatus", "false");
String targetUrl = "/";
redirectStrategy.sendRedirect(request, response, targetUrl);
}
}
check the session is true or false in every methods in the controller classes.
Controller class
if (request.getSession().getAttribute("loginStatus").equals("true"))
{
return home;
}
else
return login;
Related
I have configured the Shiro global timeout with Spring in my webapp, so if my web page(client) doesn't have any request during the past 30 minutes(just instance), the session of the client will timeout and page redirect to a login page. This is already ok. My problem is as following:
The web page has a ajax request in the background, which will request the server at set intervals. And every time it requests will clear the timeout counter of the session in Shiro, so the client session will never timeout!
Is it possible to configure the Shiro to make some specific urls will not clear or refresh the session timeout???
It's really hard to title the problem, also for searching. But I think there always are some people have the same requirement! Anyone has any idea, please tell me. Thank you very much~
My part configuration is as follows,
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="filters">
<map>
<entry key="ssl" value-ref="sslFilter"/>
<entry key="login" value-ref="userLoginFilter"/>
<entry key="nosessi" value-ref="unSessionFilter"/>
</map>
</property>
<property name="securityManager" ref="securityManager"/>
<property name="filterChainDefinitions">
<value>
/alarms/current-alarm-states = nosessi
/js/** = anon
/css/** = anon
/images/** = anon
/login = anon,ssl
/login/** = anon,ssl
/** = login,ssl
</value>
</property>
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms">
<list>
<ref bean="userRealm"/>
</list>
</property>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="sessionListeners">
<list>
<ref bean="sessionListener"/>
<ref bean="tsSessionListener"/>
</list>
</property>
<!-- 3 minutes: 180000 -->
<property name="globalSessionTimeout" value="180000"/>
<property name="sessionIdCookie.name" value="MY_SESSIONID"/>
</bean>
You can't configure this in Shiro. The timeout has nothing to do with shiro, it is a servlet container configuration.
The user session is one single object in the server and as long as your requests send the session cookie (JSESSIONID most of the time) and the servlet container can find the session object (and thus it hasn't timed out yet), the timeout will be reset.
You will have to create some Filter yourself to keep track of a timeout. For each request you can create a session timer using a session listener (http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpSessionListener.html). You could use a Timer object for this for example. Each time a request comes in, the filter gets the session timer and resets it, except on those url's you do not want that to happen.
You could also look in the source code of Vaadin, as they have a similar setup and have somehow dealt with it: https://vaadin.com/book/-/page/application.lifecycle.html#application.lifecycle.ui-expiration
I debug the shiro, track the behavior of session. And I found that the last accessed time was updated in class ShiroFilterFactoryBean, after that, Most Filters will check the request time with lastAccessTime of session except anon filter.
Based on this, I figured out a solution. Extend the ShiroFilterFactoryBean and override the method of updating session access time which will not update for the special url. Besides, the special has to use anon filter.
public class MyShiroFilterFactoryBean extends ShiroFilterFactoryBean {
#Override
protected AbstractShiroFilter createInstance() throws Exception {
SecurityManager securityManager = this.getSecurityManager();
String manager1;
if(securityManager == null) {
manager1 = "SecurityManager property must be set.";
throw new BeanInitializationException(manager1);
} else if(!(securityManager instanceof WebSecurityManager)) {
manager1 = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(manager1);
} else {
FilterChainManager manager = this.createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
return new NmsShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
}
}
#Override
public Class getObjectType() {
return NmsShiroFilterFactoryBean.SpringShiroFilter.class;
}
private static final class SpringShiroFilter extends AbstractShiroFilter {
protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
if(webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
} else {
this.setSecurityManager(webSecurityManager);
if(resolver != null) {
this.setFilterChainResolver(resolver);
}
}
}
#Override
protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
if(request instanceof HttpServletRequest) {
String requestURI = ((HttpServletRequest) request).getRequestURI();
if(requestURI.equals("/alarms/current-alarm-states")) { // no update the last access time of session
return;
}
}
super.updateSessionLastAccessTime(request, response);
}
}
}
I am discovering oauth2. I have managed to create a sample which return JWToken and REST protected by this token.
Now i would like to improve this by adding access-control in my protected REST interface.
Why ? Because i would like users like ADMIN, READER access some URL or not.
Following http://projects.spring.io/spring-security-oauth/docs/oauth2.html
it is possible over expression-handler in http node.
Here is the configuration i have added to my xml config :
<sec:global-method-security
pre-post-annotations="enabled" />
<sec:http pattern="/protected/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint">
<sec:anonymous enabled="false" />
<sec:intercept-url pattern="/protected/**" />
<sec:custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
<sec:expression-handler ref="myexpressionHandler" />
</sec:http>
<bean id="myexpressionHandler" class="org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler">
</bean>
log :
févr. 04, 2015 4:09:31 PM org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParser parse
INFOS: Expressions were enabled for method security but no SecurityExpressionHandler was configured. All hasPermision() expressions will evaluate to false.
févr. 04, 2015 4:09:31 PM org.springframework.security.config.http.HttpSecurityBeanDefinitionParser checkFilterChainOrder
But with my JWTtoken I successfully get the protected resource.
My controller:
#Component
#RestController
#RequestMapping(value = "/protected")
public class HelloWorldRest {
private static final Logger LOG = LoggerFactory
.getLogger(HelloWorldRest.class);
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#PreAuthorize("#oauth2.clientHasRole('ROLE_ADMIN')")
#RequestMapping(value = "/greeting/{name}")
public Greeting greeting(#PathVariable String name) {
LOG.info("Fonction greeting : " + name);
return new Greeting(counter.incrementAndGet(), String.format(template,
name + ", I am Mister Toto"));
}
}
I have tested with an user who get authoritiesGrant={ ROLE_NONE }
Thanks,
Any ideas ?
To avoid the error message "SecurityExpressionHandler was configured" you should add the expression handler to your global-method-security. Like this:
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="oauthExpressionHandler" />
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler" />
Instead of defining your own bean for the WebSecurityExpressionHandler (as you dod in the question) you can additionally use:
<oauth:web-expression-handler id="oauthWebExpressionHandler" />
I am learning the spring mvc and when i try to use the ConversionService ,i encounterrd 500
#RequestMapping("/handle81")
public String handle81(#RequestParam("user")User user,ModelMap modelMap) {
System.out.println(user);
modelMap.put("user", user);
return "/user/success";
}
this is the handler method ,i've put the #RequestMapping("/user") at the class
and the converter
public class StringToUserConverter implements Converter<String, User> {
public User convert(String source) {
System.out.println(source);
User user=new User();
String[] item=source.split(":");
user.setUserName(item[0]);
user.setPassword(item[1]);
user.setName(item[2]);
return user;
}
}
<mvc:annotation-driven conversion-service="conversionService" />
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.baobaotao.domain.StringToUserConverter" />
</list>
</property>
</bean>
so when i browse
http://localhost:8080/spring-mvc/user/handle81.html?user=asdf:asdf:fdas
it gets 500 and prints nothing at the console(i use maven-jetty to do the test)
thx for helping~
I think your Request URL may not be not matching. You specify "/handle81" in the annotation, but are requesting "/handle81.html".
It's hard to tell, without further information, whether the problem is matching & dispatching the request to the handler; or in the conversion.
Try another handler with the parameter of type String, and see whether you can call that successfully. At least you'll then know where the problem is.
And what is the exception stack-trace? Why didn't you post it? That's your most important clue & you should always post the ex message & top few lines/ where it was thrown, when you ask a question. It should be in either the application or Tomcat/ other server logs.
I'm building a simple Sring MVC app. And now i'm trying to add Spring security. I've added a customUserDetailsService that uses a DAO to access a MySql database and get users.
#Transactional(readOnly = true)
public class CustomUserDetailService implements UserDetailsService {
#EJB(name = "UserDAOLocal")
UserDAOLocal dao = null;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
System.out.println("Checking if this is invoked")
UserDetails user = null;
DBUsers dbUser = dao.findUserName(username);
user = new User(dbUser.getUserName(), dbUser.getPassword(), true, true, true, true, getAuthorities(dbUser.getAccess()));
return user;
}
private GrantedAuthority[] getAuthorities(Integer access) {
GrantedAuthority[] authList = new GrantedAuthority[2];
authList[0] = new GrantedAuthorityImpl("ROLE_USER");
if (access.compareTo(1) == 0) {
authList[1] = new GrantedAuthorityImpl(("ROLE_ADMIN"));
}
return authList;
}
}
And i've added the UserDetailsService to the Spring-security.xml.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="customUserDetailsService"/>
</security:authentication-manager>
<bean id="customUserDetailsService" class="service.CustomUserDetailService"/>
I put j_spring_security_check as the action to the login form on the login.jsp page.
When i enter a valid username and a password the app always tells it's wrong. What's more is i can't find any evidence that the customUserDetailsService is running at anytime. (I used System.out.println("Checking if this is invoked") to check on the server).
What invokes the loadUserByUsername() method of the CustomUserDetailsService? When is it invoked?
How can i configure it?
(All the codes i supplied might be unnecessary :))
EDIT:
Here is the rest of the Spring-Security.xml
<security:http auto-config="true">
<security:intercept-url pattern="/AddEmployee.htm" access="ROLE_ADMIN"/>
<security:intercept-url pattern="/FireEmployee.htm" access="ROLE_ADMIN"/>
<security:intercept-url pattern="/employees.htm" access="ROLE_USER"/>
<security:form-login login-page="/login.htm"
authentication-failure-url="/login.htm?error=true"
login-processing-url="/j_spring_security_check.htm"
default-target-url="/common.htm"/>
<security:logout
invalidate-session="true"
logout-success-url="/login.htm"
logout-url="/logout.htm"/>
</security:http>
I worked around the problem by editing the authentication provider like this. I decided not use DAO, and user database. and used hard coded users inside the xml file
<security:authentication-provider>
<security:user-service>
<security:user name="sam" password="sam123" authorities="ROLE_ADMIN,ROLE_USER" />
<security:user name="pam" password="pam123" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
This works perfectly.
But i would like to know why my customUserDetailService was never used, And learn how to use it correctly.
Sharing more config. from Spring-security.xml would help(if possible)
Spring security is Designed so that your Authentication provider calls loadUserByUsername() method of the UserDetailsService which returns userDetails Object.
Process is as follows:
Task of Authentication Manager is to Authenticate the user. So it sends the user name to Authentication provider.
Authentication Provider calls loadUserByUsername() method and passes user name of type String which returns userDetails Object.
Now this userDetails object contains all necessary information for authentication, such as username, password, isEnabled etc.
Now if you want to customize userDetailsService for using your Dao you can customize it.
This is how your authentication process works.
You can refer this link for broader understanding.
I am using WSO2-EI 6.4.0. I have tried this development with link. It work for me. But I need to get user name and password from other back end service. In this example was showed the hard corded user and password. I have added that code for your reference. Please help me to get those user name and password from property file.
public boolean processSecurity(String credentials) {
String decodedCredentials = new String(new Base64().decode(credentials.getBytes()));
String usernName = decodedCredentials.split(":")[0];
String password = decodedCredentials.split(":")[1];
if ("admin".equals(username) && "admin".equals(password)) {
return true;
} else {
return false;
}
}
I have added WSO2 EI handler like following. I need to pass the value from back service or call other sequence and load.
<api context="/test">
<resource methods="POST">
<inSequence>
................
</inSequence>
<outSequence>
................
</outSequence>
</resource>
<handlers>
<handler class="rezg.ride.common.BasicAuthHandler">
<property name="cm_password" value="admin"/>
<property name="cm_userName" value="admin"/>
</handler>
</handlers>
</api>
When we run the above API, handlers are running first and then running in and out sequences. So I need to get user name and password calling Sequence or any other method before run this BasicAuthHandler.
If you need to read the property file from the class mediator it's just straight forward java property file reading. Please refer the following call sample of reading a property file. In this scenario, Just read the carbon.properties file exists in the conf directory.
public boolean mediate(MessageContext context) {
String passwordFileLocation = System.getProperty("conf.location")+"/carbon.properties";
try (FileInputStream input = new FileInputStream(passwordFileLocation)) {
Properties prop = new Properties();
// load a properties file
prop.load(input);
log.info("------org.wso2.CipherTransformation : " + prop.getProperty("org.wso2.CipherTransformation"));
} catch (IOException ex) {
ex.printStackTrace();
}
return true;
}
To get the server location and the conf locating, There are JAVA system properties are set at the time wso2 server starts. Following are some of the useful System system properties.
carbon.local.ip
carbon.home
conf.location