Avoid double authentication when using custom bean spring security - java

I have a login form that calls a certain LoginBean, which returns a ajax callback parameter indicating whether the credentials are valid or not.
The code is as follows:
public void doLogin() {
Authentication authenticationRequestToken =
new UsernamePasswordAuthenticationToken(user, password);
try {
Authentication authenticationResponseToken =
authenticationManager.authenticate(authenticationRequestToken);
SecurityContextHolder.getContext().
setAuthentication(authenticationResponseToken);
if (authenticationResponseToken.isAuthenticated()) {
RequestContext context = RequestContext.getCurrentInstance();
FacesMessage msg;
boolean loggedIn = true;
msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Welcome", user);
FacesContext.getCurrentInstance().addMessage(null, msg);
context.addCallbackParam("loggedIn", loggedIn);
}
} .authenticate(...) catches ...
// Here I need some code that continue whatever j_spring_security_check
// would do after authenticating.
}
The way my application is working now, after this call to doLogin(), the form is submited to j_spring_security_check, and then the authentication process takes place again, wasting previous work.
I'm trying to find a solution for this, any help is appreciated.
So, the bottom line is that I need something that would simulate what happens when j_spring_security_check is intercepted by the filters (or a way to force this interception explicitly), so the processing would take place behind the button, not after the form is submited.

It will be better if you just forward to the spring security authentication url instead of using the SecurityContextHolder yourself. Look at this code:
public String doLogin() throws ServletException, IOException {
FacesContext context = FacesContext.getCurrentInstance();
String springCheckUrl = this.buildSpringSecurityCheckUrl();
HttpServletRequest request = (HttpServletRequest) context
.getExternalContext().getRequest();
RequestDispatcher dispatcher = request
.getRequestDispatcher(springCheckUrl);
dispatcher.forward((ServletRequest) request,
(ServletResponse) context.getExternalContext.getResponse());
context.responseComplete();
return null;
}
private String buildSpringSecurityCheckUrl() {
StringBuilder springCheckUrl = new StringBuilder(
"/j_spring_security_check").append("?").append("j_username")
.append("=").append(this.userName.trim()).append("&")
.append("j_password").append("=")
.append(this.userPassword.trim());
return springCheckUrl.toString();
}
}

Related

How to access the logged in principal from HttpSessionListener with Java EE Security?

I have an application with #CustomFormAuthenticationMechanismDefinition, and I would like to log the username, session id, IP address, etc. both at login and at logout. The HttpAuthMechanism that gets applied with this annotation associate the given session with the principal, which I can access through the SecurityContext. With a direct logout, I have no problem logging, but I would also like to log when session times out. So I created a HttpSessionListener and in its sessionDestroyed() method I try to access the logged in user through SecurityContext, but it returns an empty set, maybe because the securityContext got invalidated already.
One solution I have in my mind is to store the user principal in a session parameter (which likely happens with the HttpAuthMechanism implementation) and access it from there from the HttpSessionEvent object, but that doesn't feel like the cleanest solution. Is there another Listener I can use or some other solution?
I went with the custom HttpAuthenticationMechanism, here is it if anyone would need it (though I would be more than glad to have some feedback on whether or not it has any security flaws, or improvements).
In an #ApplicationScoped class implementing HttpAuthenticationMechanism:
#Override
public AuthenticationStatus validateRequest(HttpServletRequest request, HttpServletResponse response, HttpMessageContext httpMessageContext) throws AuthenticationException {
if (!httpMessageContext.isProtected()) {
return httpMessageContext.doNothing();
}
HttpSession session = request.getSession(false);
Credential credential = httpMessageContext.getAuthParameters().getCredential();
// If we already have a session, we get the user from it, unless it's a new login
if (session != null && !(credential instanceof UsernamePasswordCredential)) {
User user = (User) session.getAttribute("user");
if (user != null) {
return httpMessageContext.notifyContainerAboutLogin(user, user.getRoles());
}
}
// If we either don't have a session or it has no user attribute, we redirect/forward to login page
if (!(credential instanceof UsernamePasswordCredential)) {
return redirect(request, response, httpMessageContext);
}
// Here we have a Credential, so we validate it with the registered IdentityStoreHandler (injected as idStoreHandler)
CredentialValidationResult validate = idStoreHandler.validate(credential);
Context context = new Context();
context.setIp(request.getRemoteAddr());
if (validate.getStatus() == CredentialValidationResult.Status.VALID) {
session = request.getSession(true);
CallerPrincipal callerPrincipal = validate.getCallerPrincipal();
session.setAttribute("user", callerPrincipal);
context.setUser(callerPrincipal);
context.setSessionId(session.getId());
Logger log = new Logger(logger, "validateRequest", context);
log.debug("Logged in user: " + callerPrincipal.getName());
String redirectPage = "whatYouWant.xhtml";
redirect(request, response, httpMessageContext, redirectPage);
return httpMessageContext.notifyContainerAboutLogin(validate);
} else if (validate.getStatus() == CredentialValidationResult.Status.NOT_VALIDATED) {
return redirect(request, response, httpMessageContext);
} else {
// Logging
return httpMessageContext.responseUnauthorized();
}
}
And in an implemented HttpSessionListener:
#Override
public void sessionDestroyed(HttpSessionEvent se) {
User user = (User) se.getSession().getAttribute("user");
if (user != null) {
// logging
}
}

Setting a Attribute for Every Request (Spring REST)

I am doing a rest app in spring and i have a log out method like below. I dont have knowledge on spring so i just searched around and made this.
#RestController
public class LogoutController {
#Autowired
private DatabaseService databaseService;
#RequestMapping(value = "/myApp/user/logout", method = GET, produces = {"application/xml"})
public Users performLogout(#RequestHeader("AuthenticationID") String authID, HttpServletRequest request) throws DatatypeConfigurationException {
return handleLogout(request, authID);
}
private Users handleLogout(HttpServletRequest request, String authID) throws DatatypeConfigurationException {
LogService.info(this.getClass().getName(), "Received Logout Request");
final UsersXMLBuilder usersXMLBuilder = new UsersXMLBuilder();
Users usersXML = usersXMLBuilder.buildDefaultUsersTemplate();
HttpSession session = request.getSession();
AppUtilities utils = new AppUtilities();
try {
//Checking with RegEX
if (utils.isValidUUID(authToken)) {
//Get User Login Record from DB By the AuthID and Delete It
//Invalidate The Session
session.invalidate();
LogService.info(this.getClass().getName(), "Session Invaliated");
} else {
LogService.info(this.getClass().getName(), "Invalid AuthID Found. Not a Valid UUID");
usersXML.setResponseCode(-5);
usersXML.setResponseText("User Session is Not Valid");
}
} catch (Exception ex) {
LogService.error(this.getClass().getName(), ex);
usersXML.setResponseCode(-4);
usersXML.setResponseText("Error Occured!");
return usersXML;
} finally {
LogService.info(this.getClass().getName(), "LogOut Process Finished");
}
return usersXML;
}
}
Questions
1- Is it possible i can return a XML message when spring gives white label error page when i pass no authentication ID in request.
2- How can i get the Authentication Header and check it for null and give message that AuthID is missing.
3- How can i set a attribute explicitly and check for it in every controller that if it exists or not.
4- I plan to have a table where i can store user login time and give a session 10 mins time and Update it more 10 mins if i get any request from the user with the AuthID. So can i have a class or method which can check any incoming request? so i can detect the AuthID and Update My table.
Thank you for your time and help.
You can use an interceptor for that : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor
The interceptor will run for every request. It can stop the request and do a response itself.

How to add a cookie using doTag method in custom tag?

I have developed a custom tag library in Java which I use in my web application.
I am not sure why but my doTag() is not setting up cookie at all. I have cleared my cache and restarted my computer as well. Here is the code:
public class UserVersionOfSite extends EvenSimplerTagSupport {
private static final Log logger = LogFactory.getLog(UserVersionOfSite.class);
private StringWriter sw = new StringWriter();
#Override
public void doTag() throws IOException, JspException {
getJspBody().invoke(sw); //get the tag body and put it in StringWriter object
//get request object to get cookie value
PageContext ctx = (PageContext)getJspContext();
HttpServletRequest httpServletRequest = (HttpServletRequest) ctx.getRequest();
HttpServletResponse httpServletResponse = (HttpServletResponse) ctx.getResponse();
if(httpServletRequest.getParameterMap().containsKey("show_full_site")) {
logger.debug("show_full_site ");
if(!checkIfCookieExists(httpServletRequest)){
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
httpServletResponse.addCookie(cookie);
//write the tag output
if(!httpServletRequest.getParameter("show_full_site").equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}else{
String cookieValueString = getCookieValue(httpServletRequest.getCookies(),"SHOW_FULL_SITE","false");
if(!cookieValueString.equalsIgnoreCase("true")){
//write the response
getJspContext().getOut().println(sw.toString());
}
}
}
}
#Override
public String getResult() throws IOException {
return "User version of site";
}
public String getCookieValue(Cookie[] cookies,
String cookieName,
String defaultValue) {
for(int i=0; i<cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName()))
return(cookie.getValue());
}
return(defaultValue);
}
public boolean checkIfCookieExists(HttpServletRequest httpServletRequest){
logger.debug("inside checkIfCookieExists()");
boolean cookiePresent = Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
return cookiePresent;
}
}
Even I tried adding the code without using if else statements but still no success. Is there any thing critical I am missing?
Any ideas guys??!!! I have checked the browser's setting as well, but there is nothing there which is blocking a creation of cookie!
I realise the horse has probably bolted by the time I'm posting this but, for the benefit of others stumbling across it, I think the problem may be related to the feature of RequestDispatcher highlighted in this question: unable to add a cookie included in JSP via jsp:include
your following line inside checkIfCookieExists() method is wrong:
Arrays.asList(httpServletRequest.getCookies()).contains( "SHOW_FULL_SITE" );
HttpServletRequest.getCookies() returns Cookie[]. You are wrapping it inside a List and checking for a string "SHOW_FULL_SITE" inside this.
Coming back to your question- how do you know cookie is not being set in the HTTP headers? Try using browser plugins like firebug to see the HTTP response headers coming from server. Also set the path of cookie before adding it to response e.g.
Cookie cookie = new Cookie("SHOW_FULL_SITE",httpServletRequest.getParameter("show_full_site"));
cookie.setMaxAge(86400);
cookie.setPath("/");

encodeRedirectURL changes some characters

I have an Interceptor on Struts2, and I want for some pages to redirect to the ssl version of them.
Example: http://localhost/xhtml/path.do?ossesionid=value1 to https://localhost/xhtml/path.do?ossesionid=value1
For doing this I created a Interceptor that does this:
public String intercept(ActionInvocation invocation) throws Exception {
// initialize request and response
final ActionContext context = invocation.getInvocationContext();
final HttpServletRequest request = (HttpServletRequest) context
.get(StrutsStatics.HTTP_REQUEST);
final HttpServletResponse response = (HttpServletResponse) context
.get(StrutsStatics.HTTP_RESPONSE);
// check scheme
String scheme = request.getScheme().toLowerCase();
// check method
String method = request.getMethod().toUpperCase();
// If the action class uses the SSLProtected marker annotation, then see
// if we need to
// redirect to the SSL protected version of this page
if (invocation.getAction() instanceof SSLProtected) {
if (HTTP_GET.equals(method) && SCHEME_HTTP.equals(scheme)) {
// initialize https port
String httpsPortParam = request.getSession().getServletContext().getInitParameter(HTTP_PORT_PARAM);
int httpsPort = httpsPortParam == null ? HTTPS_PORT : Integer.parseInt(httpsPortParam);
response.setCharacterEncoding("UTF-8");
URI uri = new URI(SCHEME_HTTPS, null, request.getServerName(), httpsPort, response.encodeRedirectURL(request.getRequestURI()), request.getQueryString(), null);
log.debug("Going to SSL mode, redirecting to " + uri.toString());
response.sendRedirect(uri.toString());
return null;
}
}
My problem is that I expect this
https://localhost/xhtml/path.do?ossesionid=value1
and got
https://localhost/xhtml/path.do;jsessionid=value1?osessionid=value1
And I'm Completly lost! help anyone?
i strongly suggest you to use S2-SSL plugin which is more flexible and provides a much better support to handle switch from SSL to non-SSL and vice-versa.
regarding generation of Jsessionid,JSESSIONID cookie is created/sent when session is created. Session is created when your code calls request.getSession() or request.getSession(true) for the first time. If you just want get session.You have ways to disable the creation of Jsessionid
There are number of way you can disable the creation of this id, please refer to this discussion thread.
I am still not sure what is the problem you are facing with this session-id as it is a very common case in web applications
is-it-possible-to-disable-jsessionid-in-tomcat-servlet

Navigate to external URL from a backing bean?

I'm trying to implement proper logout for my Java EE / JSF2 application.
It requires two things:
I need to logout from JAAS and invalidate the session
I then have to navigate to an external URL to fire Siteminder logout
The Siteminder logout URL (configured on the Policy server -> I cannot change it) is outside my applications context. Eg. if my webapp URL is https://localhost:8080/sm/MyWebApp then the logout URL is https://localhost:8080/anotherwebapp/logout.html.
This is the current local logout code:
public void logout() {
System.out.println("Logging out...");
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
try {
request.logout();
} catch (ServletException e) {
e.printStackTrace();
}
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
if (session != null) {
session.invalidate();
}
}
And here is the property that produces the logout URL:
public String getLogoutUrl() {
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
String requestServer = request.getServerName();
String requestScheme = request.getScheme();
int serverPort = request.getServerPort();
String logoutUrl = requestScheme + "://" + requestServer + ":" + Integer.toString(serverPort) + "/anotherwebapp/logout.html";
return logoutUrl;
}
However, I cannot find a JSF2 / Primefaces component that can call logout() then open the external URL. For example, if I have:
<h:outputLink value="#{authBean.logoutUrl}" onclick="#{authBean.logout()}">[Logout]</h:outputLink>
then onclick does not seem to be called.
Another way I tried was putting the external URL to the end of the logout function to have it returned as a navigation string but it is not recognized (also tried with "?faces-redirect=true"...).
Any help would be appreciated.
You can also just use ExternalContext#redirect().
public void logout() throws ServletException, IOException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
((HttpServletRequest) ec.getRequest()).logout();
ec.invalidateSession();
ec.redirect("http://example.com/anothercontext/logout");
}
No need for an intermediating page with a meta refresh.
You can create a page logout.xhtml, so the code will look like this:
public String getLogoutUrl() {
return "/logout.jsf";
}
and in the page add:
<META HTTP-EQUIV="Refresh" CONTENT="0;URL=https://localhost:8080/anotherwebapp/logout.html">

Categories

Resources