I'm new to Spring. I can't logout with spring security.
Login works fine, and I'm following this post to implement the logout function.
but I can't make it work.
here's my spring-security.xml:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/index" access="hasRole('ROLE_USER')" />
<security:logout logout-success-url="/index" logout-url="/logout" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="matt3o" password="secret" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
and here's my index.jsp:
<c:if test="${pageContext.request.userPrincipal.name != null}">
<h2>Welcome : ${pageContext.request.userPrincipal.name}
</c:if>
<p>Logout</p>
Please can somebody explain to me how loggin/loggout works and why my logout doesn't ?
In index.jsp I'm trying to logout in different ways, none of them works:
<!--1-->
<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
Logout
</c:if>
<br><br>
<!--2-->
logout1
<br><br>
<!--3-->
<a href='<c:url value="j_spring_security_logout" />'>logout</a>
Spring Security 4 requires a POST request to logout instead of a GET. Next to that by default it is secured using a CSFR token, which you would need to add to the form (see the javadoc).
So instead of a link use a form to invoke the logout.
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
or when using the security tag library
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}" method="post">
<input type="submit" value="Log out" />
<sec:csrfInput />
</form>
See also here and here in the reference guide.
If you want to use a GET either configure the logout functionality as such that it supports GET requests (for this you need to provide an ant matcher) or by disabling CSFR which can be done by adding <sec:csfr disabled="true" /> to your xml configuration.
you can use
href="<c:url value="/logout"/>"
I've got this .xhtml file for the registration page:
<h:inputSecret id="password"
value="#{registraCliente.password}"
required="true"
binding="#{password}"
requiredMessage="Password obbligatoria"
validatorMessage="Password non valida">
<f:validateRegex pattern="(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/)" />
</h:inputSecret>
<h:message for="password" style="color:red" />
<h:inputSecret id="confermaPassword"
required="true"
value="#{registraCliente.confermaPassword}"
requiredMessage="Devi inserire di nuovo la password">
<f:validator validatorId="passwordValidator" />
<f:attribute name="password" value="#{password}" />
</h:inputSecret>
<h:message for="confermaPassword" style="color:red" />
and I want this: if the two input passwords are different, it shows me an error. But if they're the same, then the registration is allowed.
I've also added a validateRegex tag to check the "strength" of the password, but that's when I got some problems.
When I start the server and fill the form (writing the same password in both input text), it should register but it doesn't, it remains on the same xhtml page.
Eclipse's console gives me this warning:
cannot validate component with empty value: j_id_4:confermaPassword
How it comes?
The passwordValidator (link in the comments below) is a bean that implements Validator, I copied it from a blog post of Balusc, who's a JSF guru I should say :D
With a simple form when i submit I see 2 request being made for this.
<h:form id="form1">
<a4j:commandButton value="Send" id="cm1" onclick="sendData(193)"/>
<a4j:jsFunction name="sendData">
<a4j:param name="param1" assignTo="#{outageManagementAction.deleteEngineId}" />
</a4j:jsFunction>
</h:form>
The code generated by JSF is following...
<form id="form1" name="form1" method="post" action="/moutagev1/faces/pages/xOutageEdit.xhtml" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="form1" value="form1" />
<input id="form1:cm1" name="form1:cm1" onclick="jsf.util.chain(this,event,"sendData(193)","RichFaces.ajax(\"form1:cm1\",event,{\"incId\":\"1\"} )");return false;" value="Send" type="submit" /><span id="form1:j_idt257" style="display: none;"><script type="text/javascript">sendData=function(param1){RichFaces.ajax("form1:j_idt257",null,{"parameters":{"param1":param1} ,"incId":"1"} )};</script></span><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="8425501786648002013:2772799535475824519" autocomplete="off" />
</form>
Any Idea why this is happening...
Well, one request is the standard post of the <h:form> the second one is the custom <a4j:jsFunction> which is chained together with the submit when the click happens.
One solution would be to suppress the standard submit by changing the type of the button like this: <a4j:commandButton type="button" />.
Another alternative would be to not use <a4j:jsFunction> at all. Instead use this:
<f:setPropertyActionListener target="#{outageManagementAction.deleteEngineId}" value="193" />
How do I add the spring security login form to an existing page?
For example, let's say I have the following test.jsp page (which is not a spring login form page):
<html>
<head>Existing Page</head>
<body>
<div id="login-form"></div>
</body>
</html>
I would like to add the login form configured in my spring-security.xml inside the login-form div.
Typically I believe people just put the form right in the page (i.e. within the div you have there.) Something like:
<form id="blah" action="/j_spring_security_check">
<input type="text" name="j_username" />
<input type="text" name="j_password" />
<input type="submit" name="submit" value="login" />
<input type="reset" name="reset" />
</form>
Then use your css to make it fit the look and feel of the rest of your application.
I have a Facelets subview at /subviews/document-tree.xhtml that renders a tree for each tab on a <rich:tabPanel> client. The page and sub views are based on JSF 2 and RichFaces 4.
<ui:composition ...>
<rich:tree value="#{rootNode}" var="treeNode" id="#{treeId}">
<rich:treeNode ... id="chapternode">
<h:panelGrid columns="2">
<rich:outputText value="#{treeNode.name}" />
<h:commandLink>
<h:graphicImage library="images/icons" name="delete.png" />
<rich:componentControl target="remove-chapter-popup" operation="show" />
</h:commandLink>
<rich:popupPanel modal="true"
onmaskclick="#{rich:component('remove-chapter-popup')}.hide(); return false;"
id="remove-chapter-popup">
<f:facet name="header">
<h:outputText value="Remove chapter?" />
</f:facet>
<f:facet name="controls">
<h:outputText value="X" />
</f:facet>
<p>Remove chapter #{treeNode.name}?</p>
<h:panelGrid columns="2">
<h:commandButton value="Add"
action="#{nodeManager.removeChapterNode(treeNode)}"
onclick="#{rich:component('remove-chapter-popup')}.hide(); return true;">
<!--f:ajax execute="#this" render="#form" /--> <!-- never executed! -->
<a4j:ajax execute="#this" render="#form" /> <!-- this works however! -->
</h:commandButton>
<h:commandButton value="Cancel"
onclick="#{rich:component('remove-chapter-popup')}.hide(); return false;" immediate="true" />
</h:panelGrid>
</rich:popupPanel>
</h:panelGrid>
</rich:treeNode>
...
</rich:tree>
</ui:composition>
This basically shows tree nodes with their name plus an image to the right for deletion.
Each tree sub view is placed into a <rich:tab>, so the tab panel does have the required enclosing <h:form>. There are no other nested forms (forbidden anyway).
The #{nodeManager.removeChapterNode(treeNode)} bean was correctly marked as #ViewScoped.
Now what happens is kinda strange:
When using <f:ajax execute="#this" ... /> the button never executes, whereas using <a4j:ajax execute="#this" ... /> always works.
Why? What's wrong here?
It doesn't make much sense, given the fact that RichFaces <a4j:ajax> is based 100% on JSF 2 <f:ajax> according to their own words.
Could it be a bug in JSF 2.1.7, which I'm using? (the implementation that came with JBoss AS 7.1.1.Final)
Spaces are illegal in IDs. See also UIComponent#setId() javadoc.
setId
public abstract void setId(java.lang.String id)
Set the component identifier of this UIComponent (if any). Component identifiers must obey the following syntax restrictions:
Must not be a zero-length String.
First character must be a letter or an underscore ('_').
Subsequent characters must be a letter, a digit, an underscore ('_'), or a dash ('-').
Component identifiers must also obey the following semantic restrictions (note that this restriction is NOT enforced by the setId() implementation):
The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer.
Parameters:
id - The new component identifier, or null to indicate that this UIComponent does not have a component identifier
Throws:
IllegalArgumentException - if id is not syntactically valid
Seems like that RichFaces is never validating it according the rules for the tree. I would in turn account it as a bug in RichFaces. Report it to the RichFaces guys.
Here's the reduced diff:
<form id="tree-form" name="tree-form" method="post" action="/pqgenerator2/debug.jsf" enctype="application/x-www-form-urlencoded">
...
<table style="margin: 0 auto;">
<tbody>
<tr>
- <td><input id="tree-form:sorting-tree-one:real root:j_idt34" type="submit" name="tree-form:sorting-tree-one:real root:j_idt34" value="Fortfahren" onclick="jsf.util.chain(this,event,'RichFaces.$(\'tree-form:sorting-tree-one:real root:add-root-chapter-popup\').hide(); return true;','mojarra.ab(this,event,\'action\',\'#this tree-form:sorting-tree-one:real root:new-root-chapter-name-input\',\'#form\')');return false" /></td>
+ <td><input id="tree-form:sorting-tree-one:real root:j_idt34" type="submit" name="tree-form:sorting-tree-one:real root:j_idt34" value="Fortfahren" onclick="jsf.util.chain(this,event,'RichFaces.$(\'tree-form:sorting-tree-one:real root:add-root-chapter-popup\').hide(); return true;','RichFaces.ajax(this,event,{"parameters":{"javax.faces.behavior.event":"action","org.richfaces.ajax.component":"tree\\u002Dform:sorting\\u002Dtree\\u002Done:real root:j_idt34"} ,"sourceId":this} )');return false" /></td>
</tr>
</tbody>
</table>
...
- </div></span></span></div></div><input type="hidden" name="tree-form:sorting-tree-one__SELECTION_STATE" id="tree-form:sorting-tree-one__SELECTION_STATE" class="rf-tr-sel-inp" value="" /><script type="text/javascript">new RichFaces.ui.Tree("tree\u002Dform:sorting\u002Dtree\u002Done",{"toggleType":"client"} );</script></div></div><script type="text/javascript">new RichFaces.ui.Tab("tree\u002Dform:j_idt21",{"index":0,"leave":null,"togglePanelId":"tree\u002Dform:tree\u002Dtabpanel","switchMode":"client","name":"Blah GmbH","enter":null,"disabled":false} )</script></div><script type="text/javascript">new RichFaces.ui.Tab("tree\u002Dform:j_idt21",{"index":0,"leave":null,"togglePanelId":"tree\u002Dform:tree\u002Dtabpanel","switchMode":"client","name":"Blah GmbH","enter":null,"disabled":false} )</script></div><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="998210192617713914:-9142017502724223608" autocomplete="off" />
+ </div></span></span></div></div><input type="hidden" name="tree-form:sorting-tree-one__SELECTION_STATE" id="tree-form:sorting-tree-one__SELECTION_STATE" class="rf-tr-sel-inp" value="" /><script type="text/javascript">new RichFaces.ui.Tree("tree\u002Dform:sorting\u002Dtree\u002Done",{"toggleType":"client"} );</script></div></div><script type="text/javascript">new RichFaces.ui.Tab("tree\u002Dform:j_idt21",{"index":0,"leave":null,"togglePanelId":"tree\u002Dform:tree\u002Dtabpanel","switchMode":"client","name":"Blah GmbH","enter":null,"disabled":false} )</script></div><script type="text/javascript">new RichFaces.ui.Tab("tree\u002Dform:j_idt21",{"index":0,"leave":null,"togglePanelId":"tree\u002Dform:tree\u002Dtabpanel","switchMode":"client","name":"Blah GmbH","enter":null,"disabled":false} )</script></div><input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="-5805340602741883884:1908800949269113937" autocomplete="off" />
</form>
The problem here is that I create a dummy root node for the RichFaces root to be displayed and I add the real root via RichFaces TreeNodeImpl's addChild("real root", ...), which contains a space in the key.
The <a4j:ajax> code can obviously handle this but not JSF 2's <f:ajax> (note the first diff part).