Test Failed
Push — master ( cfc629...7c8fa2 )
by Misagh
14:48
created

buildDuoFlowRegistry(MultifactorAuthenticationProvider)   A

Complexity

Conditions 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 8
rs 9.4285
1
package org.apereo.cas.adaptors.duo.web.flow.config;
2
3
import org.apereo.cas.adaptors.duo.authn.DuoCredential;
4
import org.apereo.cas.configuration.CasConfigurationProperties;
5
import org.apereo.cas.configuration.model.support.mfa.DuoSecurityMultifactorProperties;
6
import org.apereo.cas.services.MultifactorAuthenticationProvider;
7
import org.apereo.cas.services.VariegatedMultifactorAuthenticationProvider;
8
import org.apereo.cas.web.flow.configurer.AbstractMultifactorTrustedDeviceWebflowConfigurer;
9
import org.apereo.cas.web.flow.CasWebflowConstants;
10
import org.apereo.cas.web.flow.configurer.DynamicFlowModelBuilder;
11
import org.slf4j.Logger;
12
import org.slf4j.LoggerFactory;
13
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
14
import org.springframework.context.ApplicationContext;
15
import org.springframework.webflow.config.FlowDefinitionRegistryBuilder;
16
import org.springframework.webflow.definition.registry.FlowDefinitionRegistry;
17
import org.springframework.webflow.engine.builder.FlowBuilder;
18
import org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder;
19
import org.springframework.webflow.engine.builder.support.FlowBuilderServices;
20
import org.springframework.webflow.engine.model.AbstractActionModel;
21
import org.springframework.webflow.engine.model.AbstractStateModel;
22
import org.springframework.webflow.engine.model.ActionStateModel;
23
import org.springframework.webflow.engine.model.BinderModel;
24
import org.springframework.webflow.engine.model.BindingModel;
25
import org.springframework.webflow.engine.model.EndStateModel;
26
import org.springframework.webflow.engine.model.EvaluateModel;
27
import org.springframework.webflow.engine.model.TransitionModel;
28
import org.springframework.webflow.engine.model.VarModel;
29
import org.springframework.webflow.engine.model.ViewStateModel;
30
import org.springframework.webflow.engine.model.builder.DefaultFlowModelHolder;
31
import org.springframework.webflow.engine.model.registry.FlowModelHolder;
32
33
import java.util.LinkedList;
34
35
/**
36
 * This is {@link DuoMultifactorWebflowConfigurer}.
37
 *
38
 * @author Misagh Moayyed
39
 * @since 5.0.0
40
 */
41
public class DuoMultifactorWebflowConfigurer extends AbstractMultifactorTrustedDeviceWebflowConfigurer {
42
    private static final Logger LOGGER = LoggerFactory.getLogger(DuoMultifactorWebflowConfigurer.class);
43
    private static final String STATE_ID_VIEW_LOGIN_FORM_DUO = "viewLoginFormDuo";
44
45
    private final VariegatedMultifactorAuthenticationProvider provider;
46
47
    public DuoMultifactorWebflowConfigurer(final FlowBuilderServices flowBuilderServices, 
48
                                           final FlowDefinitionRegistry loginFlowDefinitionRegistry,
49
                                           final boolean enableDeviceRegistration, 
50
                                           final VariegatedMultifactorAuthenticationProvider provider,
51
                                           final ApplicationContext applicationContext,
52
                                           final CasConfigurationProperties casProperties) {
53
        super(flowBuilderServices, loginFlowDefinitionRegistry, enableDeviceRegistration, applicationContext, casProperties);
54
        this.provider = provider;
55
    }
56
57
    @Override
58
    protected void doInitialize() {
59
        provider.getProviders().forEach(p -> {
60
            final FlowDefinitionRegistry duoFlowRegistry = buildDuoFlowRegistry(p);
61
            applicationContext.getAutowireCapableBeanFactory().initializeBean(duoFlowRegistry, p.getId());
62
            final ConfigurableListableBeanFactory cfg = (ConfigurableListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
63
            cfg.registerSingleton(p.getId(), duoFlowRegistry);
64
            registerMultifactorProviderAuthenticationWebflow(getLoginFlow(), p.getId(), duoFlowRegistry);
65
        });
66
67
        casProperties.getAuthn().getMfa().getDuo()
68
                .stream()
69
                .filter(DuoSecurityMultifactorProperties::isTrustedDeviceEnabled)
70
                .forEach(duo -> {
71
                    final String id = duo.getId();
72
                    try {
73
                        LOGGER.debug("Activating multifactor trusted authentication for webflow [{}]", id);
74
                        final FlowDefinitionRegistry registry = applicationContext.getBean(id, FlowDefinitionRegistry.class);
75
                        registerMultifactorTrustedAuthentication(registry);
76
                    } catch (final Exception e) {
77
                        LOGGER.error("Failed to register multifactor trusted authentication for " + id, e);
78
                    }
79
                });
80
    }
81
82
    private FlowDefinitionRegistry buildDuoFlowRegistry(final MultifactorAuthenticationProvider p) {
83
        final DynamicFlowModelBuilder modelBuilder = new DynamicFlowModelBuilder();
84
        
85
        createDuoFlowVariables(modelBuilder);
86
        createDuoFlowStartActions(modelBuilder);
87
        createDuoFlowStates(modelBuilder);
88
89
        return createDuoFlowDefinitionRegistry(p, modelBuilder);
90
    }
91
92
    private FlowDefinitionRegistry createDuoFlowDefinitionRegistry(final MultifactorAuthenticationProvider p, final DynamicFlowModelBuilder modelBuilder) {
93
        final FlowModelHolder holder = new DefaultFlowModelHolder(modelBuilder);
94
        final FlowBuilder flowBuilder = new FlowModelFlowBuilder(holder);
95
        final FlowDefinitionRegistryBuilder builder = new FlowDefinitionRegistryBuilder(this.applicationContext, flowBuilderServices);
96
        builder.addFlowBuilder(flowBuilder, p.getId());
97
        return builder.build();
98
    }
99
100
    private void createDuoFlowStates(final DynamicFlowModelBuilder modelBuilder) {
101
        final LinkedList<AbstractStateModel> states = new LinkedList<>();
102
103
        ///////////////
104
        
105
        ActionStateModel actModel = new ActionStateModel(CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
106
        LinkedList<AbstractActionModel> actions = new LinkedList<>();
107
        actions.add(new EvaluateModel("initializeLoginAction"));
108
        actModel.setActions(actions);
109
110
        LinkedList<TransitionModel> trans = new LinkedList<>();
111
        TransitionModel transModel = new TransitionModel();
112
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUCCESS);
113
        transModel.setTo("determineDuoUserAccount");
114
        trans.add(transModel);
115
116
        actModel.setTransitions(trans);
117
        states.add(actModel);
118
119
        ///////////////
120
121
        actModel = new ActionStateModel("determineDuoUserAccount");
122
        actions = new LinkedList<>();
123
        actions.add(new EvaluateModel("determineDuoUserAccountAction"));
124
        actModel.setActions(actions);
125
126
        trans = new LinkedList<>();
127
        transModel = new TransitionModel();
128
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUCCESS);
129
        transModel.setTo("determineDuoRequest");
130
        trans.add(transModel);
131
132
        transModel = new TransitionModel();
133
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_ENROLL);
134
        transModel.setTo("redirectToDuoRegistration");
135
        trans.add(transModel);
136
        
137
        actModel.setTransitions(trans);
138
        states.add(actModel);
139
        
140
        ////////////
141
        
142
        actModel = new ActionStateModel("determineDuoRequest");
143
        actions = new LinkedList<>();
144
        actions.add(new EvaluateModel("checkWebAuthenticationRequestAction"));
145
        actModel.setActions(actions);
146
147
        trans = new LinkedList<>();
148
149
        transModel = new TransitionModel();
150
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_YES);
151
        transModel.setTo(STATE_ID_VIEW_LOGIN_FORM_DUO);
152
        trans.add(transModel);
153
154
        transModel = new TransitionModel();
155
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_NO);
156
        transModel.setTo("doNonWebAuthentication");
157
        trans.add(transModel);
158
159
        actModel.setTransitions(trans);
160
        states.add(actModel);
161
162
        ///////////////
163
164
        actModel = new ActionStateModel("doNonWebAuthentication");
165
        actions = new LinkedList<>();
166
        actions.add(new EvaluateModel("duoNonWebAuthenticationAction"));
167
        actModel.setActions(actions);
168
169
        trans = new LinkedList<>();
170
171
        transModel = new TransitionModel();
172
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUCCESS);
173
        transModel.setTo("finalizeAuthentication");
174
        trans.add(transModel);
175
176
        actModel.setTransitions(trans);
177
        states.add(actModel);
178
179
        ///////////////
180
181
        actModel = new ActionStateModel("finalizeAuthentication");
182
        actions = new LinkedList<>();
183
        actions.add(new EvaluateModel("duoAuthenticationWebflowAction"));
184
        actModel.setActions(actions);
185
186
        trans = new LinkedList<>();
187
188
        transModel = new TransitionModel();
189
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUCCESS);
190
        transModel.setTo(CasWebflowConstants.TRANSITION_ID_SUCCESS);
191
        trans.add(transModel);
192
193
        actModel.setTransitions(trans);
194
        states.add(actModel);
195
196
        /////////////////
197
198
        final ViewStateModel viewState = new ViewStateModel(STATE_ID_VIEW_LOGIN_FORM_DUO);
199
        viewState.setView("casDuoLoginView");
200
        viewState.setModel(CasWebflowConstants.VAR_ID_CREDENTIAL);
201
        final BinderModel bm = new BinderModel();
202
        final LinkedList<BindingModel> bindings = new LinkedList<>();
203
        final BindingModel bme = new BindingModel("signedDuoResponse", null, null);
204
        bindings.add(bme);
205
        bm.setBindings(bindings);
206
        viewState.setBinder(bm);
207
208
        actions = new LinkedList<>();
209
        actions.add(new EvaluateModel("prepareDuoWebLoginFormAction"));
210
        viewState.setOnEntryActions(actions);
211
212
        transModel = new TransitionModel();
213
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUBMIT);
214
        transModel.setTo(CasWebflowConstants.STATE_ID_REAL_SUBMIT);
215
        transModel.setBind(Boolean.TRUE.toString());
216
        transModel.setValidate(Boolean.FALSE.toString());
217
218
        trans.add(transModel);
219
        viewState.setTransitions(trans);
220
        states.add(viewState);
221
222
        /////////////////
223
224
        actModel = new ActionStateModel(CasWebflowConstants.STATE_ID_REAL_SUBMIT);
225
        actions = new LinkedList<>();
226
        actions.add(new EvaluateModel("duoAuthenticationWebflowAction"));
227
        actModel.setActions(actions);
228
229
        trans = new LinkedList<>();
230
231
        transModel = new TransitionModel();
232
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_SUCCESS);
233
        transModel.setTo(CasWebflowConstants.TRANSITION_ID_SUCCESS);
234
        trans.add(transModel);
235
236
        transModel = new TransitionModel();
237
        transModel.setOn(CasWebflowConstants.TRANSITION_ID_ERROR);
238
        transModel.setTo(CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM);
239
        trans.add(transModel);
240
241
        actModel.setTransitions(trans);
242
        states.add(actModel);
243
244
        ////////////////////
245
246
        final ViewStateModel endModel = new ViewStateModel("redirectToDuoRegistration");
247
        endModel.setView("externalRedirect:#{flowScope.duoRegistrationUrl}");
248
        states.add(endModel);
249
        
250
        ////////////////////
251
        states.add(new EndStateModel(CasWebflowConstants.TRANSITION_ID_SUCCESS));
252
253
        ////////////////////
254
        modelBuilder.setStates(states);
255
    }
256
257
    private void createDuoFlowStartActions(final DynamicFlowModelBuilder modelBuilder) {
258
        final LinkedList<AbstractActionModel> starts = new LinkedList<>();
259
        starts.add(new EvaluateModel("initialFlowSetupAction"));
260
        modelBuilder.setOnStartActions(starts);
261
    }
262
263
    private void createDuoFlowVariables(final DynamicFlowModelBuilder modelBuilder) {
264
        final LinkedList<VarModel> vars = new LinkedList<>();
265
        vars.add(new VarModel(CasWebflowConstants.VAR_ID_CREDENTIAL, DuoCredential.class.getName()));
266
        modelBuilder.setVars(vars);
267
    }
268
}
269