Spring Security Remember me with custom authentication provider - spring-security

I am using GWT with spring security. I have a custom authentication provider where I perform all my authentication. How can I configure the remember me feature without using the UserDetailsService? I am not using LDAP.
My AppliationContext_security.xml
<http auto-config="true" entry-point-ref="UnauthorizedEntryPoint"
create-session="always">
<form-login authentication-success-handler-ref="authenticationSuccessHandler"
authentication-failure-handler-ref="authenticationFailureHandler" />
<logout success-handler-ref="logoutSuccessHandler"
invalidate-session="true" />
<intercept-url pattern="/**/myapp.rpc" access="ROLE_USER" />
<custom-filter before="CONCURRENT_SESSION_FILTER" ref="XSRFAttackFilter" />
</http>
<authentication-manager>
<authentication-provider ref="myAuthenticationProvider" />
</authentication-manager>
In my custom authentication provider,
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
boolean response = loginmanager.authenticateUser(username, password,
((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest().getSession());
if (!response) {
throw new BadCredentialsException(
"Invalid Credentials.");
}
Authentication authentication = ...
authentication.setAuthenticated(true);
return authentication;
}
Any help will be greatly appreciated.

You will need to create a custom UserDetailsService that gets the username/password from the same place that your loginmanager is reading it from. See the source for TokenBasedRememberMeServices.processAutoLoginCookie() to see how it's being used.

Related

Spring Security Struts 1.3 integration without extending GrandAuthority and UserDetails

I am new to spring security and wanted to integrate it into existing Struts 1.3 webapp.
I successfully followed this tutorial and it works great when it is that simple.
However in the tutorial user is hardcoded into security.xml:
<authentication-manager>
<authentication-provider>
<password-encoder hash="md5"/>
<user-service>
<user name="admin" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
If I understand correctly to enable custom authentication I need to implement my CustomAuthenticationProvider that extends AuthenticationProvider interface, which has an authenticate method.
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
...
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
However UsernamePasswordAuthenticationToken accepts Collection in its constructor and in our model entities do not extend spring security interaces, such as UserDetails and GrantedAuthority.
So is there a way to authenticate user without extending spring security interfaces in my entities?
EDIT:
I have added customUserDetailService:
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.do" access="isAnonymous()"/>
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
<intercept-url pattern="/j_spring_security_check" access="permitAll"/>
<form-login login-page="/login.do"
authentication-failure-url="/login.do?login_error=1"
default-target-url="/index.do"/>
<logout invalidate-session="true"
logout-url="/logout.do"
logout-success-url="/"/>
<csrf />
<remember-me />
<access-denied-handler error-page="/denied"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailService" />
</authentication-manager>
<beans:bean id="customUserDetailService" class="com.demo.service.CustomUserDetailsService"/>
However loadUserByUsername() method is not invoked...

Spring-security not working, need help understanding why

I'm trying to understand Spring-security but my pages can be accessed without loggin in and I don't understand why.
The "secure" page is located in WEB-INF/pages/secure and is accessed using http://localhost:8080/secret. This should not allow access, but currently does.
/secure maps here
#Controller
public class HelloWorld {
...
#RequestMapping("/secret")
public String showSecret(ModelMap model) {
return "secure/secretPage";
}
}
web.xml
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
/WEB-INF/springmvc-config.xml
</param-value>
</context-param>
...
applicationContext-security.xml
<http auto-config="true">
<form-login login-processing-url="/j_spring_security_check"
login-page="/login"
authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/j_spring_security_logout"/>
<intercept-url pattern="/pages/secure/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userAccountDetailsService"/>
</authentication-manager>
userAccountDetailsService
#Service("userAccountDetailsService") // enables component to be found to <component-scan/>
public class UserAccountDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
throw new UsernameNotFoundException("Could not find user");
}
}
The /login page does not currently exist. There are no users anyway. I just want this to disallow access for now.
The URL you are hitting is /secure, not /pages/secure and yet in your Spring Security configuration you are protecting /pages/secure/** instead of /secure/**. Change the intercept URL from /pages/secure/** to /secure/** and try again.

Spring security access denied message when accessing login page after login successfully.It should redirect to default page

Configured spring security successfully
Authentication properly working
Problem is that after login successfully if user access login page, access denied message appears.It must redirect to default page as user already login.
When i access login.html after login successfully , access denied message appears.
Here's my code
<http auto-config="true">
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS" />
<intercept-url pattern="/services/**" filters="none"/>
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<form-login login-page="/login.html" default-target-url="/stations.html" always-use-default-target="true" />
<logout logout-url="/logout" logout-success-url="/login.html"/>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/js/**" filters="none"/>
<intercept-url pattern="/images/**" filters="none"/>
<intercept-url pattern="/common/**" filters="none"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT USERNAME,PASSWORD,USER_STATUS as ENABLED
from USERS where USERNAME=?"
authorities-by-username-query="
SELECT USERNAME, USER_ROLE from USERS
where USERNAME =? "
/>
</authentication-provider>
</authentication-manager>
When the user successfully loggs in this means he/she has some role (admin for example). This is different than ROLE_ANONYMOUS. You can try:
<intercept-url pattern="/login.html" access="ROLE_ANONYMOUS, ROLE_ADMIN,..any other role" />
or even better
<intercept-url pattern="/login.html" filters="none" />
One suggestion: Spring Security evaluate the intercept-url elements in the order you write them in the xml, so you should put the most "greedy" intercept-url at the end. E.g. <intercept-url pattern="/**" access="ROLE_ADMIN" /> will catch everything. The intercept-url for css, js... will never be reached. You should place them first.
I face the same problem,
I have already search many resources and did not found what I looking for.
At last, I'm doing this:
public class SSOInit extends HandlerInterceptorAdapter {
private static final Logger logger = Logger.getLogger(SSOInit.class.getName());
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("### SSO : doInit, read page");
logger.info("### SSO : request url = " + request.getRequestURL());
logger.info("### SSO : request method = " + request.getMethod());
CredentialVO credential = SSOService.getUserCredential();
if (credential != null) {
logger.info("### SSO : credential found, do check point");
String status = SSOService.checkSSOSessionKey();
if (status == null || status.equals("T")) {
logger.info("### SSO : Check point didn't passed, redirect");
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
new SecurityContextLogoutHandler().logout(request, response, auth);
}
SecurityContextHolder.getContext().setAuthentication(null);
} else {
logger.info("### SSO : Check point passed");
if (request.getServletPath().equals(SSOConstant.getREDIRECT_URL())) {
logger.info("### SSO : Check point passed, user trying access login form but already authenticated, redirect");
response.sendRedirect(request.getContextPath() + SSOConstant.getMAIN_URL());
return false;
}
}
}
return super.preHandle(request, response, handler);
}
}
and add this xml configuration to dispatcher-servlet.xml
<mvc:interceptors>
<bean class="ptpn4.rawi.sso.client.authentication.SSOInit" />
</mvc:interceptors>
In class SSOInit, I do some checking to database, I'm trying to build Custom SSO Solution.
I hope another better solution regarding my current approach.

Spring security 3 http-basic authentication-success-handler

H i'm using spring security
for form-login i have
<http auto-config="true">
<intercept-url pattern="/pages/**" access="ROLE_USER" />
<form-login authentication-success-handler-ref="authenticationSuccessHandler" login-page="/login.html" default-target-url="/pages/index.html"
always-use-default-target="true" authentication-failure-url="/login.html" />
<logout logout-success-url="/login.html" invalidate-session="true" />
<anonymous enabled='false'/>
</http>
here i can set an authentication-success-handler-ref, how can i add one to my basic authentication:
<http pattern="/REST/**" realm="REALM" entry-point-ref="authenticationEntryPoint">
<intercept-url pattern="/**" access="ROLE_USER" />
<http-basic />
<logout logout-url="/REST/logout" success-handler-ref="restLogoutSuccessHandler" />
</http>
i thought abour overriding BasicAuthenticationFilter, but how can i inject my cutom class for <http-basic />
You cannot set an authentication success handler for BASIC authentication. You can, however, extend BasicAuthenticationFilter and override onSuccessfulAuthentication method:
#Component("customBasicAuthFilter")
public class CustomBasicAuthFilter extends BasicAuthenticationFilter {
#Autowired
public CustomBasicAuthFilter(AuthenticationManager authenticationManager) {
super(authenticationManager);
}
protected void onSuccessfulAuthentication(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Authentication authResult) {
// Do what you want here
}
}
Inject it in your security configuration with something like:
<http entry-point-ref="basicEntryPoint">
<custom-filter ref="customBasicAuthFilter" position="BASIC_AUTH_FILTER"/>
</http>
<authentication-manager alias="authenticationManager">
...
</authentication-manager>
Update: Or with Java config instead of XML:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAt(customBasicAuthFilter, BasicAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(basicEntryPoint);
}
As a workaround you can use http-basic in conjuction with form-login:
<http auto-config="true">
...
<http-basic />
<form-login authentication-success-handler-ref="authenticationSuccessHandler" ... />
...
</http>
BasicAuthenticationFilter will work.
EDIT.
If you want set up your overriden version of BasicAuthenticationFilter I think you need to:
Add it to filter chain at BASIC_AUTH_FILTER position as explained here
Set up corresponding BasicAuthenticationEntryPoint entry point via entry-point-ref attribute of http tag.
Instead of using an AuthenticationSuccessHandler you can rely on Spring Security's event mechanism and listen to AuthenticationSuccessEvent by using the ApplicationListener interface:
#Component
public class AuthenticationEventListener implements
ApplicationListener<AuthenticationSuccessEvent>
{
#Override
public void onApplicationEvent (AuthenticationSuccessEvent event) {
// do what you want here
// example: persist event to the database
}
}
See also this answer here: https://stackoverflow.com/a/11384001/474034

Redirecting to specific page depending upon Authentication and Authorization

I am building an Application where I am authorizing the user based on his Role. Role is defined in Ldap. We have three roles finance, cloud and sales. Depending upon the role we want to redirect to the particular page on successful login. If login fails it should redirect to some error page.
I have written the following in spring-security.xml. I am not able to redirecting to different pages .
<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 auto-config="true">
<intercept-url pattern="/finance*" access="ROLE_FINANCE" />
<logout logout-success-url="/logout" />
<intercept-url pattern="/cloud*" access="ROLE_CLOUD" />
<logout logout-success-url="/logout" />
<intercept-url pattern="/sales*" access="ROLE_SALES" />
<!-- <form-login login-page="/login1" default-target-url="/login1"
authentication-failure-url="/loginfailed" /> -->
<logout logout-success-url="/logout" />
<!-- <form-login login-page="/login.vtu" authentication-success-handler-ref="customHandler"
authentication-failure-url="/login.vtu?error=true" default-target-url="/login.vtu"
login-processing-url="/j_security_check" /> -->
</http>
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="cn=worldAdmin"
group-search-filter="(uniqueMember={0})"
group-search-base="cn=worldAdmin"
group-role-attribute="cn"
role-prefix="ROLE_">
</ldap-authentication-provider>
</authentication-manager>
<ldap-server url="ldap://localhost:12389/o=xyz" manager-dn="cn=xyzAdmin,cn=worldAdmin,o=xyz" manager-password="abc" />
</beans:beans>
Use authentication-success-handler-ref to redirect to the particular page based on User Role. (As per Spring Security, authentication-success-handler-ref Should not be used in combination with default-target-url (or always-use-default-target-url) as the
implementation should always deal with navigation to the subsequent destination)
Use authentication-failure-url to redirect when login fails:
<form-login login-page="/login.vtu" authentication-success-handler-ref="customHandler"
authentication-failure-url="/login.vtu?error=true" />
<bean id="customHandler" class="x.y.z.web.handler.CustomHandler " />
public class CustomHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
//authentication.getAuthorities() to check role
if(isFinancialRole){
response.sendRedirect(getFinancialRedirectUrl());
}
}
}
login.xhtml
<h:head >
<f:metadata>
<f:event type="preRenderView" listener="#{loginBean.onPageLoad}"/>
</f:metadata>
</h:head>
loginBean
public void onPageLoad(){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
try {
FacesContext.getCurrentInstance().getExternalContext().redirect(url);
} catch (IOException e) {
e.printStackTrace();
}
}
}

Resources