Can anybody help me understand what wrong here?
This is fragment from Spring web flow project. I create new object order and get a list of tables object from DB in tag of view state.
<?xml version="1.0" encoding="UTF-8"?>
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow.xsd">
<input name="order" required="true" />
<view-state id="chooseTable" model="flowScope.order">
<on-entry>
<set name="flowScope.order" value="new pizza.Order()"></set>
<evaluate expression="pizzaFlowActions.getFreeTables()"
result="viewScope.tables" />
</on-entry>
<transition on="chosenCreateOrder" to="bookedToOrder">
<evaluate expression="order.setTable(flowScope.order)" />
</transition>
<transition on="chosenNoOrder" to="booked">
<evaluate expression="order.setTable(flowScope.order)" />
</transition>
<transition on="cancel" to="cancel" />
</view-state>
<end-state id="cancel" />
<end-state id="bookedToOrder">
</end-state>
<end-state id="booked">
</end-state>
<global-transitions>
<transition on="cancel" to="cancel" />
</global-transitions>
</flow>
Jsp file with form with which object order is binded, and radiobuttons' values extracted from tables list.
<html xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:spring="http://www.springframework.org/tags"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:form="http://www.springframework.org/tags/form">
<jsp:output omit-xml-declaration="yes" />
<jsp:directive.page contentType="text/html;charset=UTF-8" />
<head>
<title>Book a table</title>
</head>
<body background = "${pageContext.request.contextPath}/resources/plan.gif">
<form:form commandName="order" class="box login">
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" />
<b>Choose table: </b>
<c:forEach items="${tables}" var="place">
<form:radiobutton path="table" label="${place}" value="${place}"/>
<br></br>
<br></br>
</c:forEach>
<input type="submit" class="btnLogin" name="_eventId_chosenCreateOrder" value="Now choose Pizza" />
<input type="submit" class="btnLogin" name="_eventId_chosenNoOrder" value="Just book a table" />
<input type="submit" class="btnLogin" name="_eventId_cancel" value="Cancel" />
</form:form>
</body>
</html>
Piece of Order class
public class Order implements Serializable {
private static final Logger LOGGER = getLogger(Order.class);
private int id;
private Customer customer;
private Set<Pizza> pizzas;
private Payment payment;
private Place table;
The problem here is that after choosing any variant any time the form just reloading and nothing happens more.
Will appreciate any help and hints.
I am trying to use Spring Webflow 2.3.2.
I have a legacy web flow similar to:
<start-state id-ref="A" />
<action-state id="A">
<action bean="B" />
<transition on="success" to="T" />
</action-state>
<action-state id="T">
...
</action-state>
The equivalent code that I am writing for Spring Webflow 2.3.2 is:
<on-start>
<evaluate expression="B" />
</on-start>
<action-state>
<transition on="success" to="T" />
</action-state>
<action-state id="T">
...
</action-state>
Clearly I am missing the string to connect the initial evaluation to the transition. How can I connect the two?
Let's assume your flow starts with a form
Form
<input type="hidden" name="_flowExecutionKey" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="send" /> //This starts the flow
Flow.xml
<view-state id="showForm" model="formModel">
<transition on="send" to="send2"></transition>
</view-state>
<action-state id="send2">
<evaluate expression="..."></evaluate>
<transition to="send3"></transition>
</action-state>
<view-state id="send3">
</view-state>
Based on comments from #M. Deinum, I realize that a Spring upgrade does not affect Spring webflow usage in the application. The new webflow which finally worked is:
<action-state id="A">
<evaluate expression="B" />
<transition on="success" to="T" />
</action-state>
<action-state id="T">
...
</action-state>
All that was required is to replace <action bean="B" /> with <evaluate expression="B" /> and add an id to the <action-state>.
in my scenario, user need to change password before first times login.
how to make cas redirect url before login page?
in my app, i already define my own controller to handle certain URL, and also implement my own custom authentication under authenticationHandlers.
now only left this mechanism reset password before login.
can anyone give me a clue how to do it?
my maven project file:
https://qeyg6a.bay.livefilestore.com/y2msQyFts1aCgGkYR4ybMses2mGFVNJBLCX_xQ9pDi8gVdnhx9P5ibVVBlg6p6T9RM3BAN8Qcz2Izo5JGdQzbyU-kSMTIwBVOYhkdG1RvsyE50/cas-server-webapp.rar?download&psid=1
My login-webflow.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to Jasig under one or more contributor license
agreements. See the NOTICE file distributed with this work
for additional information regarding copyright ownership.
Jasig licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a
copy of the License at the following location:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<flow xmlns="http://www.springframework.org/schema/webflow"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/webflow
http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd">
<var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" />
<on-start>
<evaluate expression="initialFlowSetupAction" />
</on-start>
<decision-state id="ticketGrantingTicketExistsCheck">
<if test="flowScope.ticketGrantingTicketId != null" then="hasServiceCheck" else="gatewayRequestCheck" />
</decision-state>
<decision-state id="gatewayRequestCheck">
<if test="requestParameters.gateway != '' and requestParameters.gateway != null and flowScope.service != null" then="gatewayServicesManagementCheck" else="serviceAuthorizationCheck" />
</decision-state>
<decision-state id="hasServiceCheck">
<if test="flowScope.service != null" then="renewRequestCheck" else="viewGenericLoginSuccess" />
</decision-state>
<decision-state id="renewRequestCheck">
<if test="requestParameters.renew != '' and requestParameters.renew != null" then="serviceAuthorizationCheck" else="generateServiceTicket" />
</decision-state>
<!-- Do a service authorization check early without the need to login first -->
<action-state id="serviceAuthorizationCheck">
<evaluate expression="serviceAuthorizationCheck"/>
<transition to="generateLoginTicket"/>
</action-state>
<!--
The "warn" action makes the determination of whether to redirect directly to the requested
service or display the "confirmation" page to go back to the server.
-->
<decision-state id="warn">
<if test="flowScope.warnCookieValue" then="showWarningView" else="redirect" />
</decision-state>
<!--
<action-state id="startAuthenticate">
<action bean="x509Check" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="warn" to="warn" />
<transition on="error" to="generateLoginTicket" />
</action-state>
-->
<!--
LPPE transitions begin here: You will also need to
move over the 'lppe-configuration.xml' file from the
'unused-spring-configuration' folder to the 'spring-configuration' folder
so CAS can pick up the definition for the bean 'passwordPolicyAction'.
-->
<action-state id="passwordPolicyCheck">
<evaluate expression="passwordPolicyAction" />
<transition on="showWarning" to="passwordServiceCheck" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="viewLoginForm" />
</action-state>
<action-state id="passwordServiceCheck">
<evaluate expression="sendTicketGrantingTicketAction" />
<transition to="passwordPostCheck" />
</action-state>
<decision-state id="passwordPostCheck">
<if test="flowScope.service != null" then="warnPassRedirect" else="pwdWarningPostView" />
</decision-state>
<action-state id="warnPassRedirect">
<evaluate expression="generateServiceTicketAction" />
<transition on="success" to="pwdWarningPostView" />
<transition on="error" to="generateLoginTicket" />
<transition on="gateway" to="gatewayServicesManagementCheck" />
</action-state>
<end-state id="pwdWarningAbstractView">
<on-entry>
<set name="flowScope.passwordPolicyUrl" value="passwordPolicyAction.getPasswordPolicyUrl()" />
</on-entry>
</end-state>
<end-state id="pwdWarningPostView" view="casWarnPassView" parent="#pwdWarningAbstractView" />
<end-state id="casExpiredPassView" view="casExpiredPassView" parent="#pwdWarningAbstractView" />
<end-state id="casMustChangePassView" view="casMustChangePassView" parent="#pwdWarningAbstractView" />
<end-state id="casAccountDisabledView" view="casAccountDisabledView" />
<end-state id="casAccountLockedView" view="casAccountLockedView" />
<end-state id="casBadHoursView" view="casBadHoursView" />
<end-state id="casBadWorkstationView" view="casBadWorkstationView" />
<!-- LPPE transitions end here... -->
<action-state id="generateLoginTicket">
<evaluate expression="generateLoginTicketAction.generate(flowRequestContext)" />
<transition on="generated" to="viewLoginForm" />
</action-state>
<view-state id="viewLoginForm" view="casLoginView" model="credentials">
<binder>
<binding property="username" />
<binding property="password" />
</binder>
<on-entry>
<set name="viewScope.commandName" value="'credentials'" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="realSubmit">
<evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" />
</transition>
</view-state>
<action-state id="realSubmit">
<evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" />
<!--
To enable LPPE on the 'warn' replace the below transition with:
<transition on="warn" to="passwordPolicyCheck" />
CAS will attempt to transition to the 'warn' when there's a 'renew' parameter
and there exists a ticketGrantingId and a service for the incoming request.
-->
<transition on="warn" to="warn" />
<!--
To enable LPPE on the 'success' replace the below transition with:
<transition on="success" to="passwordPolicyCheck" />
-->
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="generateLoginTicket" />
<transition on="accountDisabled" to="casAccountDisabledView" />
<transition on="mustChangePassword" to="casMustChangePassView" />
<transition on="accountLocked" to="casAccountLockedView" />
<transition on="badHours" to="casBadHoursView" />
<transition on="badWorkstation" to="casBadWorkstationView" />
<transition on="passwordExpired" to="casExpiredPassView" />
</action-state>
<action-state id="sendTicketGrantingTicket">
<evaluate expression="sendTicketGrantingTicketAction" />
<transition to="serviceCheck" />
</action-state>
<decision-state id="serviceCheck">
<if test="flowScope.service != null" then="generateServiceTicket" else="viewGenericLoginSuccess" />
</decision-state>
<action-state id="generateServiceTicket">
<evaluate expression="generateServiceTicketAction" />
<transition on="success" to ="warn" />
<transition on="error" to="generateLoginTicket" />
<transition on="gateway" to="gatewayServicesManagementCheck" />
</action-state>
<action-state id="gatewayServicesManagementCheck">
<evaluate expression="gatewayServicesManagementCheck" />
<transition on="success" to="redirect" />
</action-state>
<action-state id="redirect">
<evaluate expression="flowScope.service.getResponse(requestScope.serviceTicketId)" result-type="org.jasig.cas.authentication.principal.Response" result="requestScope.response" />
<transition to="postRedirectDecision" />
</action-state>
<decision-state id="postRedirectDecision">
<if test="requestScope.response.responseType.name() == 'POST'" then="postView" else="redirectView" />
</decision-state>
<!--
the "viewGenericLogin" is the end state for when a user attempts to login without coming directly from a service.
They have only initialized their single-sign on session.
-->
<end-state id="viewGenericLoginSuccess" view="casLoginGenericSuccessView" />
<!--
The "showWarningView" end state is the end state for when the user has requested privacy settings (to be "warned") to be turned on. It delegates to a
view defines in default_views.properties that display the "Please click here to go to the service." message.
-->
<end-state id="showWarningView" view="casLoginConfirmView" />
<end-state id="postView" view="postResponseView">
<on-entry>
<set name="requestScope.parameters" value="requestScope.response.attributes" />
<set name="requestScope.originalUrl" value="flowScope.service.id" />
</on-entry>
</end-state>
<!--
The "redirect" end state allows CAS to properly end the workflow while still redirecting
the user back to the service required.
-->
<end-state id="redirectView" view="externalRedirect:${requestScope.response.url}" />
<end-state id="viewServiceErrorView" view="viewServiceErrorView" />
<end-state id="viewServiceSsoErrorView" view="viewServiceSsoErrorView" />
<global-transitions>
<!-- CAS-1023 This one is simple - redirects to a login page (same as renew) when 'ssoEnabled' flag is unchecked
instead of showing an intermediate unauthorized view with a link to login page -->
<transition to="viewLoginForm" on-exception="org.jasig.cas.services.UnauthorizedSsoServiceException"/>
<transition to="viewServiceErrorView" on-exception="org.springframework.webflow.execution.repository.NoSuchFlowExecutionException" />
<transition to="viewServiceErrorView" on-exception="org.jasig.cas.services.UnauthorizedServiceException" />
</global-transitions>
</flow>
My Solution
create
resetPasswordView.(class)=org.springframework.web.servlet.view.JstlView
resetPasswordView.url=/WEB-INF/view/jsp/default/ui/ResetPassword.jsp
in default_views.properties
create
public class testflowAction extends AbstractAction{
private String origin;
#Override
protected Event doExecute(RequestContext rc) throws Exception {
origin = rc.getRequestParameters().get("service");
if(true)
return result("setNew");
else
return result("setNew");
}
}
in login-wenflow.xml, replace
<transition on="success" to="sendTicketGrantingTicket" /> with
<transition on="success" to="customFlowCheck" />
also add
<action-state id="customFlowCheck">
<evaluate expression="customCheckAction" />
<transition on="ok" to="sendTicketGrantingTicket" />
<transition on="setNew" to="resetPasswordView" />
</action-state>
and
<end-state id="resetPasswordView" view="resetPasswordView" />
We had similar problem in our company. The user had to be redirected to another page after successful login.
We decided to add another outcome from action state id "realSubmit", that would indicate continuation of flow.
I would suggest that you first let user to preform login, so he confirms that he's the right user. To do so you need to change submit method in your AuthenticationViaFormAction class. Then you need to destroy TGT, and redirect user to your custom Flow Action that reset password.
It would look something like this:
public final String submit(final RequestContext context, final Credentials credentials, final MessageContext messageContext) throws Exception {
(...)
//Login user, so we know that provided password is correct.
WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials));
// do custom logic, that check if it is first login attept:
if( firstLoginAttempt(credentials) {
//destroy TGT, so user won't stay logged-in after interrupting next step
centralAuthenticationService.destroyTicketGrantingTicket(ticketGrantingTicketId);
//redirect user to another action that will handle changing password
return "changePassRequired"
}
I don't know how you check if the password IS initial password, so I leave it to you. Next add transition in login-webflow.xml outcome:
<action-state id="realSubmit">
<evaluate expression="authenticationViaFormAction.submit(flowRequestContext,flowScope.credentials, messageContext)" />
<transition on="warn" to="warn" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="error" to="generateLoginTicket" />
<transition on="accountDisabled" to="casAccountDisabledView" />
<transition on="mustChangePassword" to="casMustChangePassView" />
<transition on="accountLocked" to="casAccountLockedView" />
<transition on="badHours" to="casBadHoursView" />
<transition on="badWorkstation" to="casBadWorkstationView" />
<transition on="passwordExpired" to="casExpiredPassView" />
<transition on="changePassRequired" to="changePasswordPrepare" />
</action-state>
And add custom action, you might as well use the same form as in login action so break it into two states, for example:
<view-state id="changePasswordPrepare" view="resetPasswordView">
<on-entry>
<evaluate expression="resetPasswordAction.setupForm(flowRequestContext)" />
</on-entry>
<transition on="submit" bind="true" validate="true" to="resetPasswordRealAction">
</transition>
</view-state>
<action-state id="resetPasswordRealAction">
<evaluate expression="resetPasswordAction.submit(flowRequestContext)" />
<transition on="success" to="sendTicketGrantingTicket" />
<transition on="again" to="changePasswordPrepare" />
<transition on="error" to="generateLoginTicket" />
</action-state>
resetPasswordAction.setupForm will prepare custom view with reset password form if it's needed
resetPasswordAction.submit will get variables from your form, and preform changing password.
snippet of class might look somewhat like this:
public class resetPasswordAction extends FormAction {
public final String submit(final RequestContext context) throws Exception {
final Credentials previousCredentials = context.getFlowScope().get("loginCredentials");
final String oldPass = context.getConversationScope().get("pass");
final String newPassword = context.getConversationScope().get("password");
final String newPasswordagain = context.getConversationScope().get("passwordagain");
if (!newPassword.equals(newPasswordagain) {
return "again";
}
if ( everythingIsOk(previousCredentials.getUsername(),oldPass,newPassword)) {
Credentials credentials = new UsernamePasswordCredentials();
credentials.setUsername(previousCredentials.getUsername());
credentials.setPassword(newPassword);
WebUtils.putTicketGrantingTicketInRequestScope(context, this.casService.createTicketGrantingTicket(credentials));
return "success";
}
return "error";
}
public Event setupForm(RequestContext context) throws Exception {
final Locale locale = LocaleContextHolder.getLocale();
context.getFlashScope().put("language",locale);
context.getFlashScope().put("service",context.getRequestScope().get("service");
}
}
You might as well be interested in CAM - CAS account management module, although it seems to be in early, theoretical phase.
You might as well be interested in cas 4, now in beta release as it seems to contain more elastic authentication logic. One, that you could use to do after login password reset.
I have running a CAS Server, seems that you should customize through Spring WebFlow. Follow my glue:
<action-state id="validateForgotPassword">
<on-entry>
<set name="flashScope.pmTask" value="'forceChangePassword'"/>
</on-entry>
<evaluate expression="forgotPasswordTokenValidateAction" />
<transition on="success" to="passwordManager"/>
<transition on="error" to="badForgotPasswordTokenView" />
</action-state>
You can add a JS script in succes login witch redirect a from your specific URL
document.location.href ="http://www...."
You can personnalized your processing JS.
I have main Route flow:
<view-state id="addRoute" model="route">
...
<transition on="editBlock" to="editBlock" validate="false" bind="true">
...
</transition>
</view-state>
<subflow-state id="editBlock" subflow="block">
</subflow-state>
By clicking on editBlock button I want to go over to Block Flow and edit Block.
I want to make it as Subflow.
Block Flow:
<on-start>
<set name="flowScope.id" value="requestParameters.id"/>
<evaluate expression="new java.util.ArrayList()" result="flowScope.attributes"/>
<evaluate expression="new java.util.ArrayList()" result="flowScope.visibility"/>
<set name="flowScope.folderId" value="requestParameters.folderId"/>
<set name="flowScope.path" value="requestParameters.path"/>
<evaluate expression="folderBean.treeAsMap" result="flowScope.tree" />
</on-start>
How to send parameters from the main Flow into Subflow? I need to provide 3 params:
id, folderId and path as stated above.
in your Block FLow, you can put:
<input name="id"/>
<input name="folderId"/>
<input name="path"/>
and then in your Route Flow you can use it this way:
<subflow-state id="editBlock" subflow="block">
<input name="id" value="flowScope.id"/>
<input name="folderId" value="flowScope.folderId"/>
<input name="path" value="flowScope.path"/>
</subflow-state>
also, if you call your Block Flow with parameters id=123&folderId=456&path=path then these parameters will be automatically mapped to the inputs with the same name which are set in the flowScope. So you won't need these set elements in you <on-start> anymore.
also FYI you can use <input name="visibility" type="java.util.ArrayList"/> and <input name="tree" value="folderBean.treeAsMap"/> and get rid of your <on-start> completely.
I am using spring mvc 3.0.4 and webflow 2.2.1, I config my webflow like the following:
<view-state id="createTaskDetail" model="task" view="task/createTaskDetail">
<transition on="upload" to="uploadFile" />
<transition on="revise" to="createTaskBasic" />
<transition on="publish" to="publish" />
<transition on="cancel" to="cancel" />
</view-state>
<view-state id="uploadFile" model="task" view="task/uploadFile">
<transition on="confirm" to="createTaskConfirm" >
<evaluate expression="task.processFile()"/>
</transition>
<transition on="revise" to="createTaskDetail" />
<transition on="publish" to="publish" />
<transition on="cancel" to="cancel" />
</view-state>
<view-state id="createTaskConfirm" model="task"
view="task/createTaskConfirm">
<transition on="publish" to="publish" />
<transition on="revise" to="uploadFile" />
<transition on="cancel" to="cancel" />
</view-state>
createTaskDetail is my 2nd view, when I arrived this page I can't forward or backward(When clicking button next or return or cancel). There is no js error or java exception,here is my jsp code of 2nd view:
<button type="submit" id="upload" name="_eventId_upload">next</button>
<button type="submit" name="_eventId_revise" >return</button>
<button type="submit" name="_eventId_cancel" >cancel</button>
<button type="submit" name="_eventId_publish" >publish</button>
Anyone has an idea? Thanks.
Do you have a form tag around the buttons?
<form:form modelAttribute="task">
inputs
buttons ...
</form:form>
Maybe validation errors which are not shown?