Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: missing code for platform authenticator (TouchID) #792

Merged
merged 1 commit into from
Feb 9, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from io.jans.as.server.util import ServerUtil
from io.jans.service.cdi.util import CdiUtil
from io.jans.util import StringHelper

from java.util import Arrays
from java.util.concurrent.locks import ReentrantLock
from javax.ws.rs import ClientErrorException
from javax.ws.rs.core import Response
Expand All @@ -38,12 +38,12 @@ def init(self, customScript, configurationAttributes):
self.fido2_domain = None
if configurationAttributes.containsKey("fido2_domain"):
self.fido2_domain = configurationAttributes.get("fido2_domain").getValue2()

self.metaDataLoaderLock = ReentrantLock()
self.metaDataConfiguration = None

print "Fido2. Initialized successfully"
return True
return True

def destroy(self, configurationAttributes):
print "Fido2. Destroy"
Expand All @@ -69,6 +69,7 @@ def authenticate(self, configurationAttributes, requestParameters, step):

if step == 1:
print "Fido2. Authenticate for step 1"
identity.setWorkingParameter("platformAuthenticatorAvailable",ServerUtil.getFirstValue(requestParameters, "loginForm:platformAuthenticator"))

user_password = credentials.getPassword()
logged_in = False
Expand Down Expand Up @@ -163,6 +164,12 @@ def prepareForStep(self, configurationAttributes, requestParameters, step):
assertionService = Fido2ClientFactory.instance().createAssertionService(metaDataConfiguration)
assertionRequest = json.dumps({'username': userName}, separators=(',', ':'))
assertionResponse = assertionService.authenticate(assertionRequest).readEntity(java.lang.String)
# if device has only platform authenticator and assertion is expecting a security key
if "internal" in assertionResponse:
identity.setWorkingParameter("platformAuthenticatorAvailable", "true")
else:
identity.setWorkingParameter("platformAuthenticatorAvailable", "false")

except ClientErrorException, ex:
print "Fido2. Prepare for step 2. Failed to start assertion flow. Exception:", sys.exc_info()[1]
return False
Expand All @@ -171,7 +178,20 @@ def prepareForStep(self, configurationAttributes, requestParameters, step):

try:
attestationService = Fido2ClientFactory.instance().createAttestationService(metaDataConfiguration)
attestationRequest = json.dumps({'username': userName, 'displayName': userName, 'attestation': 'direct'}, separators=(',', ':'))
platformAuthenticatorAvailable = identity.getWorkingParameter("platformAuthenticatorAvailable") == "true"
basic_json = {'username': userName, 'displayName': userName, 'attestation' : 'direct'}
print "% s" % identity.getWorkingParameter("platformAuthenticatorAvailable")
if platformAuthenticatorAvailable is True:
# the reason behind userVerification = discouraged --> https://chromium.googlesource.com/chromium/src/+/master/content/browser/webauth/uv_preferred.md
platform_json = {"authenticatorSelection":{"authenticatorAttachment":"platform","requireResidentKey" : "false", "userVerification" : "discouraged" } }
basic_json.update(platform_json)

# also need to add this --> excludeCredentials : [//registered ids]
print " basic_json %s" % basic_json

attestationRequest = json.dumps(basic_json)
#, separators=(',', ':'))

attestationResponse = attestationService.register(attestationRequest).readEntity(java.lang.String)
except ClientErrorException, ex:
print "Fido2. Prepare for step 2. Failed to start attestation flow. Exception:", sys.exc_info()[1]
Expand All @@ -190,7 +210,7 @@ def prepareForStep(self, configurationAttributes, requestParameters, step):
return False

def getExtraParametersForStep(self, configurationAttributes, step):
return None
return Arrays.asList( "platformAuthenticatorAvailable")

def getCountAuthenticationSteps(self, configurationAttributes):
return 2
Expand All @@ -199,27 +219,32 @@ def getNextStep(self, configurationAttributes, requestParameters, step):
return -1

def getPageForStep(self, configurationAttributes, step):
if step == 2:
return "/auth/fido2/login.xhtml"

if step == 1:
return "/auth/fido2/step1.xhtml"
elif step == 2:
identity = CdiUtil.bean(Identity)
if identity.getWorkingParameter("platformAuthenticatorAvailable") == "true":
return "/auth/fido2/platform.xhtml"
else:
return "/auth/fido2/secKeys.xhtml"
return ""

def logout(self, configurationAttributes, requestParameters):
return True

def getAuthenticationMethodClaims(self, requestParameters):
return None

def getLogoutExternalUrl(self, configurationAttributes, requestParameters):
print "Get external logout URL call"
return None
return None

def getMetaDataConfiguration(self):
if self.metaDataConfiguration != None:
return self.metaDataConfiguration

self.metaDataLoaderLock.lock()
# Make sure that another thread not loaded configuration already
# Make sure that another thread not loaded configuration already
if self.metaDataConfiguration != None:
return self.metaDataConfiguration

Expand All @@ -228,7 +253,7 @@ def getMetaDataConfiguration(self):
self.fido2_server_metadata_uri = self.fido2_server_uri + "/.well-known/fido2-configuration"

metaDataConfigurationService = Fido2ClientFactory.instance().createMetaDataConfigurationService(self.fido2_server_metadata_uri)

max_attempts = 10
for attempt in range(1, max_attempts + 1):
try:
Expand All @@ -238,7 +263,7 @@ def getMetaDataConfiguration(self):
# 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
finally:
Expand Down