Requesting the user to enter a security question#

The``PipeSecQuestion`` procedure checks whether the user has a security question. If the question is not asked, the procedure prompts the user to enter it.

The following modifications must be made to the procedure before use:

  • in the DOMAIN constant, specify the URI at which Blitz Identity Provider is accessible from the user’s browser;

  • in the``CAN_SKIP`` constant, specify the display mode: true– the user can skip filling; false – the user must set the value of the security question to complete authentication.

public class PipeSecQuestion implements Strategy {

    private final Logger logger = LoggerFactory.getLogger("com.identityblitz.idp.flow.dynamic");
        private final static String DOMAIN = "example.com";
    private final static Boolean CAN_SKIP = true;

    @Override public StrategyBeginState begin(final Context ctx) {
        if ("login".equals(ctx.prompt())){
            List<String> methods = new ArrayList<String>(Arrays.asList(ctx.availableMethods()));
            methods.remove("cls");
            return StrategyState.MORE(methods.toArray(new String[0]), true);
        } else {
            if(ctx.claims("subjectId") != null)
                return StrategyState.ENOUGH();
            else
                return StrategyState.MORE(new String[]{});
        }
    }

    @Override public StrategyState next(final Context ctx) {
        Integer reqFactor = (ctx.user() == null) ? null : ctx.user().requiredFactor();
        if (reqFactor == null || reqFactor.equals(ctx.justCompletedFactor())){
                if(requireAddSecQsn(ctx)) return addSecQsn(ctx);
            else return StrategyState.ENOUGH();
        }
        else  return StrategyState.MORE(new String[]{});
    }

    private Boolean requireAddSecQsn(final Context ctx) {
        String secQsn = (ctx.user() == null) ? null : ctx.user().securityQuestion();
        Long agreedOn = (ctx.user() == null) ? null : ctx.user().userProps().numProp("pipes.addSecQsn.agreedOn");
        Long disagreedOn = (ctx.user() == null) ? null : ctx.user().userProps().numProp("pipes.addSecQsn.disagreedOn");
        if (secQsn != null) return false;
        else if (disagreedOn == null) return true;
        else {
            long now = Instant.now().getEpochSecond();
            return ((now - disagreedOn) > 1);
        }
    }

    private StrategyState addSecQsn(final Context ctx) {
        String uri = "https://"+DOMAIN+"/blitz/pipes/secQsn/start?canSkip="+CAN_SKIP+"&appId=_blitz_profile";
        Set<String> claims = new HashSet<String>(){{
          add("instanceId");
        }};
        Set<String> scopes = new HashSet<String>(){{
            add("openid");
        }};
       return StrategyState.ENOUGH_BUILDER()
         .withPipe(uri, "_blitz_profile", scopes, claims)
         .build();
    }
}