def prepareForStep(self, configurationAttributes, requestParameters, step):
        identity = CdiUtil.bean(Identity)

        if step == 1:
            return True
        elif step == 2:
            print "Fido2. Prepare for step 2"

            session = CdiUtil.bean(SessionIdService).getSessionId()
            if session == None:
                print "Fido2. Prepare for step 2. Failed to determine session_id"
                return False

            authenticationService = CdiUtil.bean(AuthenticationService)
            user = authenticationService.getAuthenticatedUser()
            if user == None:
                print "Fido2. Prepare for step 2. Failed to determine user name"
                return False

            userName = user.getUserId()

            metaDataConfiguration = self.getMetaDataConfiguration()
            
            assertionResponse = None
            attestationResponse = None

            # Check if user have registered devices
            userService = CdiUtil.bean(UserService)
            countFido2Devices = userService.countFidoAndFido2Devices(userName, self.fido2_domain)
            if countFido2Devices > 0:
                print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start assertion flow"

                try:
                    assertionService = Fido2ClientFactory.instance().createAssertionService(metaDataConfiguration)
                    assertionRequest = json.dumps({'username': userName}, separators=(',', ':'))
                    assertionResponse = assertionService.authenticate(assertionRequest).readEntity(java.lang.String)
                except ClientResponseFailure, ex:
                    print "Fido2. Prepare for step 2. Failed to start assertion flow. Exception:", sys.exc_info()[1]
                    return False
            else:
                print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start attestation flow"

                try:
                    attestationService = Fido2ClientFactory.instance().createAttestationService(metaDataConfiguration)
                    attestationRequest = json.dumps({'username': userName, 'displayName': userName, 'attestation' : 'direct'}, separators=(',', ':'))
                    attestationResponse = attestationService.register(attestationRequest).readEntity(java.lang.String)
                except ClientResponseFailure, ex:
                    print "Fido2. Prepare for step 2. Failed to start attestation flow. Exception:", sys.exc_info()[1]
                    return False
    def getMetaDataConfiguration(self):
        if self.metaDataConfiguration != None:
            return self.metaDataConfiguration
        
        self.metaDataLoaderLock.lock()
        # Make sure that another thread not loaded configuration already          
        if self.metaDataConfiguration != None:
            return self.metaDataConfiguration

        try:
            print "Fido2. Initialization. Downloading Fido2 metadata"
            self.fido2_server_metadata_uri = self.fido2_server_uri + "/.well-known/fido2-configuration"
            #self.fido2_server_metadata_uri = self.fido2_server_uri + "/fido2/restv1/fido2/configuration"

            metaDataConfigurationService = Fido2ClientFactory.instance().createMetaDataConfigurationService(self.fido2_server_metadata_uri)
    
            max_attempts = 10
            for attempt in range(1, max_attempts + 1):
                try:
                    self.metaDataConfiguration = metaDataConfigurationService.getMetadataConfiguration().readEntity(java.lang.String)
                    return self.metaDataConfiguration
                except ClientResponseFailure, ex:
                    # Detect if last try or we still get Service Unavailable HTTP error
                    if (attempt == max_attempts) or (ex.getResponse().getResponseStatus() != Response.Status.SERVICE_UNAVAILABLE):
                        raise ex
    
                    java.lang.Thread.sleep(3000)
                    print "Attempting to load metadata: %d" % attempt
                except ResteasyClientException, ex:
                    # Detect if last try or we still get Service Unavailable HTTP error
                    if attempt == max_attempts:
                        raise ex
    
                    java.lang.Thread.sleep(3000)
                    print "Attempting to load metadata: %d" % attempt
    def authenticateFido2(self, userId, requestParameters):

        if REMOTE_DEBUG:
            pydevd.settrace('localhost',
                            port=5678,
                            stdoutToServer=True,
                            stderrToServer=True)

        userService = CdiUtil.bean(UserService)
        authenticationService = CdiUtil.bean(AuthenticationService)
        identity = CdiUtil.bean(Identity)
        session = identity.getSessionId()

        tokenResponse = ServerUtil.getFirstValue(requestParameters,
                                                 "fido2Authentication")
        print("%s. Authenticate. Got fido2 authentication response: %s" %
              (self.name, tokenResponse))
        metaDataConfiguration = self.getFidoMetaDataConfiguration()
        assertionService = Fido2ClientFactory.instance(
        ).createAssertionService(metaDataConfiguration)
        assertionStatus = assertionService.verify(tokenResponse)
        authenticationStatusEntity = assertionStatus.readEntity(
            java.lang.String)

        if assertionStatus.getStatus() != Response.Status.OK.getStatusCode():
            print(
                "%s. Authenticate. Got invalid authentication status from Fido2 server"
                % self.name)
            return False

        return authenticationService.authenticate(
            identity.getWorkingParameter("userId"))
    def authenticate(self, configurationAttributes, requestParameters, step):
        authenticationService = CdiUtil.bean(AuthenticationService)

        identity = CdiUtil.bean(Identity)
        credentials = identity.getCredentials()

        user_name = credentials.getUsername()

        if (step == 1):
            print "Fido2. Authenticate for step 1"

            if authenticationService.getAuthenticatedUser() != None:
                return True

            user_password = credentials.getPassword()
            logged_in = False
            if (StringHelper.isNotEmptyString(user_name)
                    and StringHelper.isNotEmptyString(user_password)):
                userService = CdiUtil.bean(UserService)
                logged_in = authenticationService.authenticate(
                    user_name, user_password)

            if (not logged_in):
                return False

            return True
        elif (step == 2):
            print "Fido2. Authenticate for step 2"

            token_response = ServerUtil.getFirstValue(requestParameters,
                                                      "tokenResponse")
            if token_response == None:
                print "Fido2. Authenticate for step 2. tokenResponse is empty"
                return False

            auth_method = ServerUtil.getFirstValue(requestParameters,
                                                   "authMethod")
            if auth_method == None:
                print "Fido2. Authenticate for step 2. authMethod is empty"
                return False

            authenticationService = CdiUtil.bean(AuthenticationService)
            user = authenticationService.getAuthenticatedUser()
            if (user == None):
                print "Fido2. Prepare for step 2. Failed to determine user name"
                return False

            if (auth_method == 'authenticate'):
                print "Fido2. Prepare for step 2. Call Fido2 in order to finish authentication flow"
                assertionService = Fido2ClientFactory.instance(
                ).createAssertionService(self.metaDataConfiguration)
                assertionStatus = assertionService.verify(token_response)
                authenticationStatusEntity = assertionStatus.readEntity(
                    java.lang.String)

                if (assertionStatus.getStatus() !=
                        Response.Status.OK.getStatusCode()):
                    print "Fido2. Authenticate for step 2. Get invalid authentication status from Fido2 server"
                    return False

                return True
            elif (auth_method == 'enroll'):
                print "Fido2. Prepare for step 2. Call Fido2 in order to finish registration flow"
                attestationService = Fido2ClientFactory.instance(
                ).createAttestationService(self.metaDataConfiguration)
                attestationStatus = attestationService.verify(token_response)

                if (attestationStatus.getStatus() !=
                        Response.Status.OK.getStatusCode()):
                    print "Fido2. Authenticate for step 2. Get invalid registration status from Fido2 server"
                    return False

                return True
            else:
                print "Fido2. Prepare for step 2. Authentication method is invalid"
                return False

            return False
        else:
            return False
    def prepareForStep(self, configurationAttributes, requestParameters, step):
        identity = CdiUtil.bean(Identity)

        if (step == 1):
            return True
        elif (step == 2):
            print "Fido2. Prepare for step 2"

            session_id = CdiUtil.bean(
                SessionIdService).getSessionIdFromCookie()
            if StringHelper.isEmpty(session_id):
                print "Fido2. Prepare for step 2. Failed to determine session_id"
                return False

            authenticationService = CdiUtil.bean(AuthenticationService)
            user = authenticationService.getAuthenticatedUser()
            if (user == None):
                print "Fido2. Prepare for step 2. Failed to determine user name"
                return False

            userName = user.getUserId()

            metaDataConfiguration = self.getMetaDataConfiguration()

            # Check if user have registered devices
            registrationPersistenceService = CdiUtil.bean(
                RegistrationPersistenceService)

            assertionResponse = None
            attestationResponse = None

            userFido2Devices = registrationPersistenceService.findAllRegisteredByUsername(
                userName)
            if (userFido2Devices.size() > 0):
                print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start assertion flow"

                try:
                    assertionService = Fido2ClientFactory.instance(
                    ).createAssertionService(metaDataConfiguration)
                    assertionRequest = json.dumps({'username': userName},
                                                  separators=(',', ':'))
                    assertionResponse = assertionService.authenticate(
                        assertionRequest).readEntity(java.lang.String)
                except ClientResponseFailure, ex:
                    print "Fido2. Prepare for step 2. Failed to start assertion flow. Exception:", sys.exc_info(
                    )[1]
                    return False
            else:
                print "Fido2. Prepare for step 2. Call Fido2 endpoint in order to start attestation flow"

                try:
                    attestationService = Fido2ClientFactory.instance(
                    ).createAttestationService(metaDataConfiguration)
                    attestationRequest = json.dumps(
                        {
                            'username': userName,
                            'displayName': userName
                        },
                        separators=(',', ':'))
                    attestationResponse = attestationService.register(
                        attestationRequest).readEntity(java.lang.String)
                except ClientResponseFailure, ex:
                    print "Fido2. Prepare for step 2. Failed to start attestation flow. Exception:", sys.exc_info(
                    )[1]
                    return False
    def prepareForStep(self, configurationAttributes, requestParameters, step):

        if REMOTE_DEBUG:
            pydevd.settrace('localhost',
                            port=5678,
                            stdoutToServer=True,
                            stderrToServer=True)

        # Inject dependencies
        identity = CdiUtil.bean(Identity)
        facesResources = CdiUtil.bean(FacesResources)
        facesService = CdiUtil.bean(FacesService)
        userService = CdiUtil.bean(UserService)

        session = identity.getSessionId()
        sessionAttributes = session.getSessionAttributes()
        externalContext = facesResources.getFacesContext().getExternalContext()
        uiLocales = sessionAttributes.get(AuthorizeRequestParam.UI_LOCALES)

        rpConfig = self.getRPConfig(session)
        clientUri = self.getClientUri(session)

        externalContext.addResponseHeader(
            "Content-Security-Policy",
            "default-src 'self' https://www.canada.ca; font-src 'self' https://fonts.gstatic.com https://use.fontawesome.com https://www.canada.ca; style-src 'self' 'unsafe-inline'; style-src-elem 'self' 'unsafe-inline' https://use.fontawesome.com https://fonts.googleapis.com https://www.canada.ca; script-src 'self' 'unsafe-inline' https://www.canada.ca https://ajax.googleapis.com; connect-src 'self' https://*.fjgc-gccf.gc.ca"
        )

        if step == 1:
            httpRequest = externalContext.getRequest()
            # Bookmark detection
            #if httpRequest.getHeader("referer") is None:
            #    if StringHelper.isNotEmpty(clientUri):
            #        facesService.redirectToExternalURL(clientUri)
            #        return True
            #    else:
            #        print("%s: prepareForStep. clientUri is missing for client %s" % (self.name, self.getClient(session).getClientName()))
            #        return False

            # forceAuthn workaround
            prompt2 = httpRequest.getParameter("prompt2")
            if prompt2 == "login":
                identity.setWorkingParameter("forceAuthn", True)

            # step could actually be 2, or 3
            if uiLocales is not None:
                if len(self.providers) > 1:
                    step = self.STEP_CHOOSER
                else:
                    step = self.STEP_1FA

        if identity.getWorkingParameter("abort"):  # Back button workaround
            # Obtain the client URI of the current client from the client configuration
            if len(self.providers
                   ) == 1:  # Pass through, so send them back to the client
                if StringHelper.isNotEmpty(clientUri):
                    facesService.redirectToExternalURL(clientUri)
                    return True
                else:
                    print(
                        "%s: prepareForStep. clientUri is missing for client %s"
                        % (self.name, self.getClient(session).getClientName()))
                    return False
            else:  # reset the chooser
                identity.setWorkingParameter("provider", None)

        if step == self.STEP_CHOOSER:
            # Prepare for chooser page customization.
            for param in ["layout", "chooser", "content"]:
                identity.setWorkingParameter(param, rpConfig[param])

        elif step in {self.STEP_1FA, self.STEP_COLLECT,
                      self.STEP_2FA}:  # Passport

            passportOptions = {
                "ui_locales": uiLocales,
                "exp": int(time.time()) + 60
            }

            if step in {self.STEP_1FA, self.STEP_COLLECT}:
                provider = identity.getWorkingParameter("provider")
                if provider is None and len(
                        self.providers
                ) == 1:  # Only one provider. Direct Pass-through
                    provider = next(iter(self.providers))
                    identity.setWorkingParameter("provider", provider)

            if step == self.STEP_1FA:
                # Coordinate single-sign-on (SSO)
                maxAge = (sessionAttributes.get(AuthorizeRequestParam.MAX_AGE)
                          or self.getClient(session).getDefaultMaxAge())
                if (identity.getWorkingParameter("forceAuthn") or
                    ("GCCF" in self.passport.getProvider(provider)["options"]
                     and maxAge < 1200)
                    ):  # 1200 is 20 minutes, the SSO timeout on GCKey and CBS
                    passportOptions["forceAuthn"] = "true"

            elif step == self.STEP_COLLECT:
                collect = rpConfig.get("collect")
                if collect is not None:
                    passportOptions["allowCreate"] = rpConfig.get(
                        "allowCreate") or "false"
                    passportOptions["spNameQualifier"] = collect
                else:  # This should never happen
                    print(
                        "%s. prepareForStep: collection entityID is missing" %
                        self.name)
                    return False

            elif step == self.STEP_2FA:
                provider = rpConfig.get("mfaProvider")
                if provider is None:
                    print("%s: prepareForStep. mfaProvider is missing!" %
                          self.name)
                    return False
                mfaId = identity.getWorkingParameter("mfaId")
                if mfaId is None:
                    print("%s: prepareForStep. mfaId is missing!" % self.name)
                    return False
                else:
                    passportOptions["login_hint"] = mfaId
                    # The following parameters are redundant, but currently required by the 2ndFaaS
                    passportOptions[
                        "redirect_uri"] = self.passport.getProvider(
                            provider)["callbackUrl"]
                    passportOptions["response_type"] = "code"
                    passportOptions["scope"] = "openid profile"

            # Set the abort flag to handle back button
            identity.setWorkingParameter("abort", True)
            # Send the request to passport
            passportRequest = self.passport.createRequest(
                provider, passportOptions)
            facesService.redirectToExternalURL(passportRequest)

        elif step in {self.STEP_FIDO_REGISTER, self.STEP_FIDO_AUTH}:
            userId = identity.getWorkingParameter("userId")
            metaDataConfiguration = self.getFidoMetaDataConfiguration()

            if step == self.STEP_FIDO_REGISTER:
                try:
                    attestationService = Fido2ClientFactory.instance(
                    ).createAttestationService(metaDataConfiguration)
                    attestationRequest = json.dumps(
                        {
                            'username': userId,
                            'displayName': userId,
                            'attestation': 'direct',
                            'timeout': 120000,
                            'userVerification': 'discouraged'
                        },
                        separators=(',', ':'))
                    attestationResponse = attestationService.register(
                        attestationRequest).readEntity(java.lang.String)
                except ClientErrorException as ex:
                    print(
                        "%s. Prepare for step. Failed to start FIDO2 attestation flow. Exception:"
                        % self.name,
                        sys.exc_info()[1])
                    return False
                identity.setWorkingParameter(
                    "fido2_attestation_request",
                    ServerUtil.asJson(attestationResponse))
                print(ServerUtil.asJson(attestationResponse))

            elif step == self.STEP_FIDO_AUTH:
                userId = identity.getWorkingParameter("userId")
                metaDataConfiguration = self.getFidoMetaDataConfiguration()
                fidoDeviceCount = userService.countFidoAndFido2Devices(
                    userId, self.fido2_domain)
                try:
                    assertionService = Fido2ClientFactory.instance(
                    ).createAssertionService(metaDataConfiguration)
                    assertionRequest = json.dumps(
                        {
                            'username': userId,
                            'timeout': 120000,
                            'userVerification': 'discouraged'
                        },
                        separators=(',', ':'))
                    assertionResponse = assertionService.authenticate(
                        assertionRequest).readEntity(java.lang.String)
                except ClientErrorException as ex:
                    print(
                        "%s. Prepare for step. Failed to start FIDO2 assertion flow. Exception:"
                        % self.name,
                        sys.exc_info()[1])
                    return False
                identity.setWorkingParameter(
                    "fido2_assertion_request",
                    ServerUtil.asJson(assertionResponse))

        return True