Yan,

Below are a couple methods I use to see the flow.

Ray


protected void flowToFile(final Flow flow, final String fileName) {
String s = flow.toString().trim();
String formatted = formatFlow(s);
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
//writer.write(s);
writer.write("\n\n\n\n");
writer.write(formatted);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
}

/**
* Formats a spring webflow flow to help determine how to modify a flow.
* Adds new lines and indents to make it easier to read.
* @param input flow.toString()
* @return nicely formatted flow
*/
public String formatFlow(final String input) {
//LOGGER.debug("input: ." + input + ".");
// used to add an extra indent for an object's field members
java.util.Stack<java.util.AbstractMap.SimpleEntry> stack = new 
java.util.Stack<>();
int currPosition = 0;
String indent = "";
String indentor = "\t";
String newLine = "\n";
// object identifier
java.util.regex.Pattern objPattern = Pattern.compile("^(\\w+@\\w+)\\b.*");

String in = input.trim();
StringBuilder out = new StringBuilder();
while (in.length() > currPosition) {
java.util.regex.Matcher m = objPattern.matcher(in.substring(currPosition));
String firstTwo = "";
// capture first two characters to match against ']' or '],'
if (1 < in.length() - currPosition) {
firstTwo = in.substring(currPosition, currPosition + 2);
} else {
// at end of input
firstTwo = in.substring(currPosition, currPosition + 1);
}
if (in.startsWith("[", currPosition)) {
out.append(indent).append(in.charAt(currPosition)).append(newLine);
indent += indentor;
currPosition++;
if (!stack.empty()) {
java.util.AbstractMap.SimpleEntry<String, Integer> se = stack.pop();
se.setValue(se.getValue() + 1);
stack.push(se);
}
} else if (firstTwo.startsWith("]")) {
if (!stack.empty()) {
java.util.AbstractMap.SimpleEntry<String, Integer> se = stack.pop();
if (1 > se.getValue()) {
// outdent after printing member variables
indent = indent.replaceFirst(indentor, "");
if (!stack.empty()) {
// this ] closes from outer object
java.util.AbstractMap.SimpleEntry<String, Integer> seOuter = stack.pop();
seOuter.setValue(seOuter.getValue() - 1);
stack.push(seOuter);
}
} else {
se.setValue(se.getValue() - 1);
stack.push(se);
}
}
indent = indent.replaceFirst(indentor, "");
out.append(indent).append("]");
if ("],".equals(firstTwo)) {
out.append(",");
currPosition++;
}
out.append(newLine);
currPosition++;
} else if (m.matches()) {
String obj = m.group(1);
out.append(indent).append(obj).append(newLine);
indent = indent + indentor;
// prepare for members
stack.push(new java.util.AbstractMap.SimpleEntry<String, Integer>(obj, 0));
currPosition += obj.length();
} else {
int nextOpenBracket = in.indexOf("[", currPosition);
int nextCloseBracket = in.indexOf("]", currPosition);
int nextComma = in.indexOf(",", currPosition);
int nextMark = 0;
boolean increaseIndent = false;
// if [ or , not found, push beyond last position which would be ]
if (0 > nextOpenBracket) {
nextOpenBracket = in.length();
}
if (0 > nextComma) {
nextComma = in.length();
}
// add 1 when [ and , since they should remain on same line and ] should be on 
next line
if (nextCloseBracket > nextOpenBracket) {
if (nextOpenBracket > nextComma) {
nextMark = nextComma + 1;
} else {
nextMark = nextOpenBracket + 1;
// bypass empty and null
if ((in.substring(nextMark).startsWith("[empty]]"))
|| (in.substring(nextMark).startsWith("null]"))) {
if (in.substring(nextMark).startsWith("[empty]],")) {
nextMark += 9;
} else if (in.substring(nextMark).startsWith("[empty]]")) {
nextMark += 8;
} else if (in.substring(nextMark).startsWith("null],")) {
nextMark += 6;
} else if (in.substring(nextMark).startsWith("null]")) {
nextMark += 5;
}
} else {
// indent members
increaseIndent = true;
if (!stack.empty()) {
java.util.AbstractMap.SimpleEntry<String, Integer> se = stack.pop();
se.setValue(se.getValue() + 1);
stack.push(se);
}
}
}
} else if (nextCloseBracket > nextComma) {
nextMark = nextComma + 1;
} else {
nextMark = nextCloseBracket;
}
String s = in.substring(currPosition, nextMark).trim();
if (0 < s.length()) {
out.append(indent).append(s).append(newLine);
currPosition = nextMark;
}
if (increaseIndent) {
// for next line
indent = indent + indentor;
}
}
}
String formatted = out.toString().trim();
//LOGGER.debug("formatted: ." + formatted + ".");

return formatted;
}

On Thu, 2021-12-16 at 16:54 -0800, Yan Zhou wrote:
Notice: This message was sent from outside the University of Victoria email 
system. Please be cautious with links and sensitive information.

Hi there,

CAS 6.4.x.  we have global MFA turned on for all requests, but we want our SSO 
traffic to skip MFA.   I run into problem with CAS looking for simple-mfa 
during our SSO login flow.  I followed the CAS' source on token authentication, 
but has not found a solution.

The following are some info.  Thanks in advance!

cas.properties:

cas.authn.mfa.triggers.global.global-provider-id=mfa-simple
cas.authn.mfa.simple.name=mfa-simple
cas.authn.mfa.simple.order=1

service json:

  "multifactorPolicy" : {
        "@class" : 
"org.apereo.cas.services.DefaultRegisteredServiceMultifactorPolicy",
        "bypassPrincipalAttributeName": "questSkipMFA"
  }

we have a separate SSO authenticationHandler that will set principal attribute, 
so that MFA module will know to skip MFA.

this is my SSO webflow, once SSO passes, we issue TGT,  and authN completes.

public class SsoLoginWebflowConfigurer  extends AbstractCasWebflowConfigurer  {
    }

    @Override
    protected void doInitialize() {
        val flow = getLoginFlow();
        if (flow != null) {
                val state = getState(flow, 
CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM, ActionState.class);
            createTransitionForState(state, 
TRANSITION_ID_SSO_AUTHENTICATION_CHECK, STATE_ID_SSO_AUTHENTICATION_CHECK);

            val actionState = createActionState(flow, 
STATE_ID_SSO_AUTHENTICATION_CHECK,
                
createEvaluateAction("oktaSamlNonInteractiveCredentialsAction"));

            createTransitionForState(actionState, 
CasWebflowConstants.TRANSITION_ID_ERROR, "lsmSAMLFailed");
            val lsmSamlFailed = createViewState(flow, "lsmSAMLFailed", 
"error/casLsmTokenErrorView");
            createStateDefaultTransition(lsmSamlFailed, "viewLoginForm");

            createTransitionForState(actionState, 
CasWebflowConstants.TRANSITION_ID_SUCCESS,
                            
CasWebflowConstants.STATE_ID_CREATE_TICKET_GRANTING_TICKET);


                   .........

here is the error I get. I looks like CAS is looking for mfa-simple state 
(probably because I have globally turned on MFA).   How can I append the 
mfa-simple flow into this flow definition?  And when I do so, I assume it will 
note the attribute and skip the actual mfa flow?

2021-12-17 00:42:17,828 DEBUG 
[org.apereo.cas.authentication.mfa.trigger.GlobalMultifactorAuthenticationTrigger]
 - <Attempting to globally activate [mfa-simple]>
2021-12-17 00:42:17,832 DEBUG 
[org.apereo.cas.authentication.mfa.trigger.GlobalMultifactorAuthenticationTrigger]
 - <Resolved single multifactor provider 
[AbstractMultifactorAuthenticationProvider(bypassEvaluator=org.apereo.cas.authentication.bypass.DefaultChainingMultifactorAuthenticationBypassProvider@673afa7f,
 
failureModeEvaluator=org.apereo.cas.authentication.DefaultMultifactorAuthenticationFailureModeEvaluator@48b482d7,
 failureMode=CLOSED, id=mfa-simple, order=0)]>
2021-12-17 00:42:17,832 TRACE 
[org.apereo.cas.authentication.MultifactorAuthenticationUtils] - <Attempting to 
find a matching transition for event id [mfa-simple]>
2021-12-17 00:42:17,833 TRACE 
[org.apereo.cas.authentication.MultifactorAuthenticationUtils] - <Reviewing 
current state [[ActionState@64f89202 id = 
'oktaSamlSSONonInteractiveCredentials', flow = 'login', entryActionList = 
list[[empty]], exceptionHandlerSet = list[[empty]], actionList = 
list[[EvaluateAction@71a47cf2 expression = 
oktaSamlNonInteractiveCredentialsAction, resultExpression = [null]]], 
transitions = list[[Transition@36169b00 on = success, to = realSubmitSamlSSO], 
[Transition@fe2f399 on = error, to = lsmSAMLFailed]], exitActionList = 
list[[empty]]]], event [oktaSAML] and transition [[Transition@37398daa on = 
oktaSAML, to = oktaSamlSSONonInteractiveCredentials]]>
2021-12-17 00:42:17,834 ERROR 
[org.apereo.cas.authentication.MultifactorAuthenticationUtils] - <State 
[oktaSamlSSONonInteractiveCredentials:oktaSAML:oktaSAML] does not have a 
matching transition for mfa-simple>
2021-12-17 00:42:17,836 DEBUG 
[org.apereo.cas.web.flow.resolver.impl.DefaultCasDelegatingWebflowEventResolver]
 - <State [oktaSamlSSONonInteractiveCredentials:oktaSAML:oktaSAML] does not 
have a matching transition for mfa-simple>


== end ==

Yan

--

Ray Bon
Programmer Analyst
Development Services, University Systems
2507218831 | CLE 019 | r...@uvic.ca<mailto:r...@uvic.ca>

I acknowledge and respect the lək̓ʷəŋən peoples on whose traditional territory 
the university stands, and the Songhees, Esquimalt and WSÁNEĆ peoples whose 
historical relationships with the land continue to this day.

-- 
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
--- 
You received this message because you are subscribed to the Google Groups "CAS 
Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to cas-user+unsubscr...@apereo.org.
To view this discussion on the web visit 
https://groups.google.com/a/apereo.org/d/msgid/cas-user/5babbc81a072f10783fca2af8797ca7e69209639.camel%40uvic.ca.

Reply via email to