Test Failed
Push — master ( c886ea...fc43c4 )
by Misagh
25:04
created

configurePasswordMustChangeForAuthnWarnings(Flow)   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
package org.apereo.cas.pm.web.flow;
2
3
import org.apereo.cas.configuration.CasConfigurationProperties;
4
import org.apereo.cas.pm.PasswordChangeBean;
5
import org.apereo.cas.pm.web.flow.actions.PasswordChangeAction;
6
import org.apereo.cas.pm.web.flow.actions.SendPasswordResetInstructionsAction;
7
import org.apereo.cas.util.CollectionUtils;
8
import org.apereo.cas.web.flow.CasWebflowConfigurer;
9
import org.apereo.cas.web.flow.CasWebflowConstants;
10
import org.apereo.cas.web.flow.configurer.AbstractCasWebflowConfigurer;
11
import org.springframework.context.ApplicationContext;
12
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
13
import org.springframework.webflow.engine.ActionState;
14
import org.springframework.webflow.engine.Flow;
15
import org.springframework.webflow.engine.SubflowState;
16
import org.springframework.webflow.engine.Transition;
17
import org.springframework.webflow.engine.TransitionableState;
18
import org.springframework.webflow.engine.ViewState;
19
import org.springframework.webflow.engine.builder.BinderConfiguration;
20
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
21
import org.springframework.webflow.execution.Action;
22
23
/**
24
 * This is {@link PasswordManagementWebflowConfigurer}.
25
 *
26
 * @author Misagh Moayyed
27
 * @since 5.0.0
28
 */
29
public class PasswordManagementWebflowConfigurer extends AbstractCasWebflowConfigurer {
30
    /**
31
     * Flow id for password reset.
32
     */
33
    public static final String FLOW_ID_PASSWORD_RESET = "pswdreset";
34
35
    /**
36
     * Flow id for password reset.
37
     */
38
    public static final String FLOW_VAR_ID_PASSWORD = "password";
39
40
    /**
41
     * Name of parameter that can be supplied to login url to force display of password change during login.
42
     */
43
    public static final String DO_CHANGE_PASSWORD_PARAMETER = "doChangePassword";
44
45
    private static final String PASSWORD_CHANGE_ACTION = "passwordChangeAction";
46
    private static final String SEND_PASSWORD_RESET_INSTRUCTIONS_ACTION = "sendInstructions";
47
48
    private final Action initPasswordChangeAction;
49
50
    public PasswordManagementWebflowConfigurer(final FlowBuilderServices flowBuilderServices,
51
                                               final FlowDefinitionRegistry loginFlowDefinitionRegistry,
52
                                               final ApplicationContext applicationContext,
53
                                               final CasConfigurationProperties casProperties,
54
                                               final Action initPasswordChangeAction) {
55
        super(flowBuilderServices, loginFlowDefinitionRegistry, applicationContext, casProperties);
56
        this.initPasswordChangeAction = initPasswordChangeAction;
57
    }
58
59
    @Override
60
    protected void doInitialize() {
61
        final Flow flow = getLoginFlow();
62
        if (flow != null) {
63
            createAccountStatusViewStates(flow);
64
        }
65
    }
66
67
    private void createAccountStatusViewStates(final Flow flow) {
68
        createViewState(flow, CasWebflowConstants.VIEW_ID_AUTHENTICATION_BLOCKED, CasWebflowConstants.VIEW_ID_AUTHENTICATION_BLOCKED);
69
        createViewState(flow, CasWebflowConstants.VIEW_ID_INVALID_WORKSTATION, CasWebflowConstants.VIEW_ID_INVALID_WORKSTATION);
70
        createViewState(flow, CasWebflowConstants.VIEW_ID_INVALID_AUTHENTICATION_HOURS,
71
                CasWebflowConstants.VIEW_ID_INVALID_AUTHENTICATION_HOURS);
72
        createViewState(flow, CasWebflowConstants.VIEW_ID_ACCOUNT_LOCKED, CasWebflowConstants.VIEW_ID_ACCOUNT_LOCKED);
73
        createViewState(flow, CasWebflowConstants.VIEW_ID_ACCOUNT_DISABLED, CasWebflowConstants.VIEW_ID_ACCOUNT_DISABLED);
74
        createViewState(flow, CasWebflowConstants.STATE_ID_PASSWORD_UPDATE_SUCCESS, CasWebflowConstants.VIEW_ID_PASSWORD_UPDATE_SUCCESS);
75
76
        if (casProperties.getAuthn().getPm().isEnabled()) {
77
            configurePasswordResetFlow(flow, CasWebflowConstants.VIEW_ID_EXPIRED_PASSWORD);
78
            configurePasswordResetFlow(flow, CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD);
79
            configurePasswordMustChangeForAuthnWarnings(flow);
80
            createPasswordResetFlow();
81
        } else {
82
            createViewState(flow, CasWebflowConstants.VIEW_ID_EXPIRED_PASSWORD, CasWebflowConstants.VIEW_ID_EXPIRED_PASSWORD);
83
            createViewState(flow, CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD, CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD);
84
        }
85
    }
86
87
    private void configurePasswordMustChangeForAuthnWarnings(final Flow flow) {
88
        final TransitionableState warningState = getTransitionableState(flow, CasWebflowConstants.VIEW_ID_SHOW_AUTHN_WARNING_MSGS);
89
        warningState.getEntryActionList().add(createEvaluateAction("flowScope.pswdChangePostLogin=true"));
90
        createTransitionForState(warningState, "changePassword", CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD);
91
    }
92
93
    private void createPasswordResetFlow() {
94
        final Flow flow = getLoginFlow();
95
        if (flow != null) {
96
            final boolean autoLogin = casProperties.getAuthn().getPm().isAutoLogin();
97
98
            final ViewState state = getState(flow, CasWebflowConstants.STATE_ID_VIEW_LOGIN_FORM, ViewState.class);
99
            createTransitionForState(state, CasWebflowConstants.TRANSITION_ID_RESET_PASSWORD,
100
                    CasWebflowConstants.VIEW_ID_SEND_RESET_PASSWORD_ACCT_INFO);
101
            final ViewState accountInfo = createViewState(flow, CasWebflowConstants.VIEW_ID_SEND_RESET_PASSWORD_ACCT_INFO,
102
                    CasWebflowConstants.VIEW_ID_SEND_RESET_PASSWORD_ACCT_INFO);
103
            createTransitionForState(accountInfo, "findAccount", SEND_PASSWORD_RESET_INSTRUCTIONS_ACTION);
104
            final ActionState sendInst = createActionState(flow, SEND_PASSWORD_RESET_INSTRUCTIONS_ACTION,
105
                    createEvaluateAction("sendPasswordResetInstructionsAction"));
106
            createTransitionForState(sendInst, CasWebflowConstants.TRANSITION_ID_SUCCESS,
107
                    CasWebflowConstants.VIEW_ID_SENT_RESET_PASSWORD_ACCT_INFO);
108
            createTransitionForState(sendInst, CasWebflowConstants.TRANSITION_ID_ERROR, accountInfo.getId());
109
            createViewState(flow, CasWebflowConstants.VIEW_ID_SENT_RESET_PASSWORD_ACCT_INFO,
110
                    CasWebflowConstants.VIEW_ID_SENT_RESET_PASSWORD_ACCT_INFO);
111
112
            final Flow pswdFlow = buildFlow("classpath:/webflow/pswdreset/pswdreset-webflow.xml", FLOW_ID_PASSWORD_RESET);
113
            createViewState(pswdFlow, "passwordResetErrorView", CasWebflowConstants.VIEW_ID_PASSWORD_RESET_ERROR);
114
            createViewState(pswdFlow, CasWebflowConstants.STATE_ID_PASSWORD_UPDATE_SUCCESS,
115
                    CasWebflowConstants.VIEW_ID_PASSWORD_UPDATE_SUCCESS);
116
            configurePasswordResetFlow(pswdFlow, CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD);
117
            loginFlowDefinitionRegistry.registerFlowDefinition(pswdFlow);
118
119
            final ActionState initializeLoginFormState = getState(flow, CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM, ActionState.class);
120
            final String originalTargetState = initializeLoginFormState.getTransition(CasWebflowConstants.STATE_ID_SUCCESS).getTargetStateId();
121
            final SubflowState pswdResetSubFlowState = createSubflowState(flow, CasWebflowConstants.STATE_ID_PASSWORD_RESET_SUBFLOW, FLOW_ID_PASSWORD_RESET);
122
123
            getTransitionableState(flow, CasWebflowConstants.STATE_ID_REAL_SUBMIT).getEntryActionList()
124
                    .add(createEvaluateAction("flowScope." + DO_CHANGE_PASSWORD_PARAMETER
125
                            + " = requestParameters." + DO_CHANGE_PASSWORD_PARAMETER + " != null"));
126
127
            createDecisionState(flow, CasWebflowConstants.CHECK_FOR_PASSWORD_RESET_TOKEN_ACTION,
128
                    "requestParameters." + SendPasswordResetInstructionsAction.PARAMETER_NAME_TOKEN + " != null",
129
                    CasWebflowConstants.STATE_ID_PASSWORD_RESET_SUBFLOW,
130
                    originalTargetState);
131
            createTransitionForState(initializeLoginFormState,
132
                    CasWebflowConstants.STATE_ID_SUCCESS,
133
                    CasWebflowConstants.CHECK_FOR_PASSWORD_RESET_TOKEN_ACTION, true);
134
            createEndState(pswdFlow, CasWebflowConstants.STATE_ID_PASSWORD_RESET_FLOW_COMPLETE);
135
            createTransitionForState(
136
                    getTransitionableState(pswdFlow, CasWebflowConstants.STATE_ID_PASSWORD_UPDATE_SUCCESS),
137
                    CasWebflowConstants.TRANSITION_ID_PROCEED,
138
                    CasWebflowConstants.STATE_ID_PASSWORD_RESET_FLOW_COMPLETE);
139
            createEndState(flow, CasWebflowConstants.STATE_ID_REDIRECT_TO_LOGIN, "'" + CasWebflowConfigurer.FLOW_ID_LOGIN + "'", true);
140
141
            createTransitionForState(
142
                    pswdResetSubFlowState,
143
                    CasWebflowConstants.STATE_ID_PASSWORD_RESET_FLOW_COMPLETE,
144
                    autoLogin ? CasWebflowConstants.STATE_ID_REAL_SUBMIT : CasWebflowConstants.STATE_ID_REDIRECT_TO_LOGIN);
145
146
            createDecisionState(flow,
147
                    CasWebflowConstants.STATE_ID_CHECK_DO_CHANGE_PASSWORD,
148
                    "flowScope." + DO_CHANGE_PASSWORD_PARAMETER + " == true",
149
                    CasWebflowConstants.VIEW_ID_MUST_CHANGE_PASSWORD,
150
                    getTransitionableState(flow, CasWebflowConstants.STATE_ID_REAL_SUBMIT)
151
                            .getTransition(CasWebflowConstants.TRANSITION_ID_SUCCESS).getTargetStateId())
152
                    .getEntryActionList().add(createEvaluateAction("flowScope.pswdChangePostLogin=true"));
153
154
            createTransitionForState(getTransitionableState(flow, CasWebflowConstants.STATE_ID_REAL_SUBMIT),
155
                    CasWebflowConstants.TRANSITION_ID_SUCCESS, CasWebflowConstants.STATE_ID_CHECK_DO_CHANGE_PASSWORD, true);
156
157
            createDecisionState(flow,
158
                    CasWebflowConstants.STATE_ID_PSWD_CHANGE_CHECK_POST_LOGIN,
159
                    "flowScope.pswdChangePostLogin == true",
160
                    getTransitionableState(flow, CasWebflowConstants.VIEW_ID_SHOW_AUTHN_WARNING_MSGS)
161
                            .getTransition(CasWebflowConstants.TRANSITION_ID_PROCEED).getTargetStateId(),
162
                    autoLogin ? CasWebflowConstants.STATE_ID_REAL_SUBMIT : CasWebflowConstants.STATE_ID_REDIRECT_TO_LOGIN);
163
164
            createTransitionForState(
165
                    getTransitionableState(flow, CasWebflowConstants.STATE_ID_PASSWORD_UPDATE_SUCCESS),
166
                    CasWebflowConstants.TRANSITION_ID_PROCEED,
167
                    CasWebflowConstants.STATE_ID_PSWD_CHANGE_CHECK_POST_LOGIN);
168
169
        }
170
    }
171
172
    private void configurePasswordResetFlow(final Flow flow, final String id) {
173
        createFlowVariable(flow, FLOW_VAR_ID_PASSWORD, PasswordChangeBean.class);
174
175
        final BinderConfiguration binder = createStateBinderConfiguration(CollectionUtils.wrapList(FLOW_VAR_ID_PASSWORD, "confirmedPassword"));
176
        final ViewState viewState = createViewState(flow, id, id, binder);
177
        createStateModelBinding(viewState, FLOW_VAR_ID_PASSWORD, PasswordChangeBean.class);
178
179
        viewState.getEntryActionList().add(this.initPasswordChangeAction);
180
        final Transition transition = createTransitionForState(viewState, CasWebflowConstants.TRANSITION_ID_SUBMIT, PASSWORD_CHANGE_ACTION);
181
        transition.getAttributes().put("bind", Boolean.TRUE);
182
        transition.getAttributes().put("validate", Boolean.TRUE);
183
184
        createStateDefaultTransition(viewState, id);
185
186
        final ActionState pswChangeAction = createActionState(flow, PASSWORD_CHANGE_ACTION, createEvaluateAction(PASSWORD_CHANGE_ACTION));
187
        pswChangeAction.getTransitionSet().add(
188
                createTransition(PasswordChangeAction.PASSWORD_UPDATE_SUCCESS, CasWebflowConstants.STATE_ID_PASSWORD_UPDATE_SUCCESS));
189
        pswChangeAction.getTransitionSet().add(createTransition(CasWebflowConstants.TRANSITION_ID_ERROR, id));
190
    }
191
}
192