From 9f3d051308e7b29e5f112e74601aa05c42ed559c Mon Sep 17 00:00:00 2001 From: Madhumita Subramaniam Date: Wed, 16 Nov 2022 12:52:02 +0530 Subject: [PATCH] fix: #2487 removing duplicated files (#3007) --- .../other/acr_router/Readme.txt | 0 .../other/allowed_countries/readme.txt | 0 .../other/basic.client_group/README.txt | 0 .../other/basic.external_logout/README.txt | 0 .../other/basic.lock.account/README.txt | 0 .../basic.multi_auth_conf/INSTALLATION.txt | 0 .../other/basic.multi_auth_conf/README.txt | 0 .../other/basic.multi_login/INSTALLATION.txt | 0 .../other/basic.multi_login/README.txt | 0 .../README.txt | 0 .../other/basic.one_session/README.txt | 0 .../other/basic.reset_to_step/README.txt | 0 .../other/bioid/README.txt | 72 + .../other/cert/Generate certs guide.md | 0 .../cert/Generate certs without configs.md | 0 .../cert/Quick certs guide for testing.md | 0 .../other/cert/README.txt | 0 .../other/compromised_password/readme.txt | 0 .../other/duo/README.txt | 0 .../other/forgot_password/README.md | 26 - .../other/forgot_password/forgot_password.py | 435 -- .../other/fortinet/README.txt | 0 .../other/gplus/README.txt | 0 .../other/idfirst/README_idfirst.md | 0 .../other/obconnect/documentation/README.txt | 0 .../documentation/larger_picture.png | Bin .../other/registration/read.txt | 0 .../other/saml/INSTALLATION.txt | 0 .../other/saml/README.txt | 0 .../other/twilio_sms/README.txt | 0 .../other/uaf/Properties description.md | 0 .../other/wwpass/INSTALLATION.md | 0 .../other/wwpass/README.md | 237 +- .../other/yubicloud/README.txt | 0 .../extension/person_authentication/README.md | 5 - .../acr_router/acr_routerauthenticator.py | 84 - .../allowed_countries/allowed_countries.py | 155 - .../other/authz/ConsentGatheringSample.py | 87 - .../other/authz/docs/Authz design.dia | Bin 4879 -> 0 bytes .../other/authz/docs/Authz design.png | Bin 26731 -> 0 bytes .../azuread/AzureADAuthenticationForGluu.py | 271 - .../other/azuread/README.md | 13 - ...asicPassowrdUpdateExternalAuthenticator.py | 124 - .../auth/pwd/new-password.xhtml | 114 - .../BasicClientGroupExternalAuthenticator.py | 177 - .../basic.client_group/client_group.json | 16 - ...ExternalAuthenticatorWithExternalLogout.py | 91 - ...BasicMultiAuthConfExternalAuthenticator.py | 293 - .../BasicMultiLoginExternalAuthenticator.py | 122 - ...TestEmailAddressesExternalAuthenticator.py | 97 - .../BasicOneSessionExternalAuthenticator.py | 118 - .../PasswordExpiration.py | 149 - .../other/basic.password_expiration/README.md | 2 - .../BasicResetToStepExternalAuthenticator.py | 100 - .../bcrypt_ssha_migration/pwd_migration.py | 148 - .../other/cas2/Cas2ExternalAuthenticator.py | 338 - .../cas2_duo/Cas2DuoExternalAuthenticator.py | 182 - .../other/cas2_duo/Readme.md | 34 - .../other/cas2_duo/docs/joinded_flows.dia | Bin 2240 -> 0 bytes .../other/cas2_duo/docs/joinded_flows.jpg | Bin 31807 -> 0 bytes .../other/cert/docs/Cert design.dia | Bin 11048 -> 0 bytes .../other/cert/docs/Cert design.jpg | Bin 110176 -> 0 bytes .../other/cert/sample/cert_creds.json | 7 - .../other/cert/sample/generated_certs.zip | Bin 53946 -> 0 bytes .../other/ciba/FirebaseEndUserNotification.py | 68 - .../compromised_password.py | 223 - .../other/custom_registration/Attributes.json | 10 - .../other/custom_registration/README.md | 11 - .../other/custom_registration/reg.xhtml | 264 - .../other/custom_registration/register.py | 268 - .../fortinet/FortinetExternalAuthenticator.py | 127 - .../gplus/GooglePlusExternalAuthenticator.py | 557 -- .../gplus/sample/custom_script_entry.ldif | 22 - .../gplus/sample/gplus_client_secrets.json | 1 - .../other/gplus/workflow.txt | 39 - .../other/idfirst/alter_login.xhtml | 156 - .../other/idfirst/idfirst.py | 98 - .../other/idfirst/idfirst_login.xhtml | 89 - .../other/obconnect/UpdateToken.py | 72 - .../obconnectExternalAuthentication.py | 246 - .../other/obconnect/redirect.xhtml | 15 - .../other/oneid/oneidlogin.xhtml | 79 - .../other/oneid/oneidpostlogin.xhtml | 91 - .../other/otp/Properties description.md | 25 - ...tp_integration_authentication_workflow.png | Bin 64598 -> 0 bytes .../0.0.1-SNAPSHOT/_remote.repositories | 6 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 36 - ...keyprovisioning-0.0.1-SNAPSHOT-javadoc.jar | Bin 71430 -> 0 bytes ...keyprovisioning-0.0.1-SNAPSHOT-sources.jar | Bin 12997 -> 0 bytes ...ath-otp-keyprovisioning-0.0.1-SNAPSHOT.jar | Bin 14268 -> 0 bytes ...ath-otp-keyprovisioning-0.0.1-SNAPSHOT.pom | 40 - .../maven-metadata-local.xml | 11 - .../0.0.1-SNAPSHOT/_remote.repositories | 6 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 36 - .../oath-otp-0.0.1-SNAPSHOT-javadoc.jar | Bin 68069 -> 0 bytes .../oath-otp-0.0.1-SNAPSHOT-sources.jar | Bin 13536 -> 0 bytes .../oath-otp-0.0.1-SNAPSHOT.jar | Bin 12279 -> 0 bytes .../oath-otp-0.0.1-SNAPSHOT.pom | 19 - .../oath/oath-otp/maven-metadata-local.xml | 11 - .../0.0.1-SNAPSHOT/_remote.repositories | 3 - .../0.0.1-SNAPSHOT/maven-metadata-local.xml | 19 - .../oath-parent-0.0.1-SNAPSHOT.pom | 182 - .../oath/oath-parent/maven-metadata-local.xml | 11 - .../other/otp/sample/otp_configuration.json | 13 - .../other/otp/sequence_diagram.txt | 31 - .../passport/PassportExternalAuthenticator.py | 631 -- .../other/passport/README.md | 10 - .../sample/passport_script_entry.ldif | 16 - .../other/phonefactor/pflogin.xhtml | 81 - .../other/postauthn/postauthn.py | 53 - .../other/registration/register.py | 181 - .../SamlPassportAuthenticator.py | 826 --- .../Gluu Inbound SAML Design (no Session).png | Bin 52535 -> 0 bytes .../other/saml/SamlExternalAuthenticator.py | 793 --- .../1.0.1.gluu/gcm-server-1.0.1.gluu.jar | Bin 28229 -> 0 bytes .../1.0.1.gluu/gcm-server-1.0.1.gluu.jar.md5 | 1 - .../1.0.1.gluu/gcm-server-1.0.1.gluu.jar.sha1 | 1 - .../1.0.1.gluu/gcm-server-1.0.1.gluu.pom | 8 - .../1.0.1.gluu/gcm-server-1.0.1.gluu.pom.md5 | 1 - .../1.0.1.gluu/gcm-server-1.0.1.gluu.pom.sha1 | 1 - .../google/gcm/gcm-server/maven-metadata.xml | 12 - .../gcm/gcm-server/maven-metadata.xml.md5 | 1 - .../gcm/gcm-server/maven-metadata.xml.sha1 | 1 - .../super_gluu/sample/super_gluu_creds.json | 43 - .../other/toopher/tpauthenticate.xhtml | 83 - .../other/toopher/tppair.xhtml | 98 - .../other/uaf/UafExternalAuthenticator.py | 398 -- ...af_integration_authentication_workflow.png | Bin 59443 -> 0 bytes .../other/uaf/img/oob_qr_code.png | Bin 77419 -> 0 bytes .../uaf/img/typical_uaf_architecture.png | Bin 11696 -> 0 bytes .../uaf/img/uaf_device_integration_models.png | Bin 31811 -> 0 bytes .../other/uaf/sequence_diagram.txt | 25 - .../other/wikid/wikidlogin.xhtml | 116 - .../other/wikid/wikidregister.xhtml | 116 - .../other/wwpass/README.md | 19 - .../wwpass/pages/auth/wwpass/checkemail.xhtml | 163 - .../wwpass/pages/auth/wwpass/wwpass.xhtml | 285 - .../wwpass/pages/auth/wwpass/wwpassbind.xhtml | 329 - .../other/wwpass/static/js/wwpass-frontend.js | 6097 ----------------- .../other/wwpass/ticket.json | 9 - .../other/wwpass/wwpass.ca.crt | 35 - .../other/wwpass/wwpass.py | 248 - .../other/wwpass/wwpassauth.py | 289 - 143 files changed, 78 insertions(+), 17274 deletions(-) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/acr_router/Readme.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/allowed_countries/readme.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.client_group/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.external_logout/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.lock.account/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.multi_auth_conf/INSTALLATION.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.multi_auth_conf/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.multi_login/INSTALLATION.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.multi_login/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.multiple_test_email_addresses/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.one_session/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/basic.reset_to_step/README.txt (100%) create mode 100644 docs/script-catalog/person_authentication/other/bioid/README.txt rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/cert/Generate certs guide.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/cert/Generate certs without configs.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/cert/Quick certs guide for testing.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/cert/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/compromised_password/readme.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/duo/README.txt (100%) delete mode 100644 docs/script-catalog/person_authentication/other/forgot_password/README.md delete mode 100644 docs/script-catalog/person_authentication/other/forgot_password/forgot_password.py rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/fortinet/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/gplus/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/idfirst/README_idfirst.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/obconnect/documentation/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/obconnect/documentation/larger_picture.png (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/registration/read.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/saml/INSTALLATION.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/saml/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/twilio_sms/README.txt (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/uaf/Properties description.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/wwpass/INSTALLATION.md (100%) rename {jans-linux-setup/jans_setup/static/extension => docs/script-catalog}/person_authentication/other/yubicloud/README.txt (100%) delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/acr_routerauthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/allowed_countries.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/ConsentGatheringSample.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/docs/Authz design.dia delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/docs/Authz design.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/azuread/AzureADAuthenticationForGluu.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/azuread/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.change_password/BasicPassowrdUpdateExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.change_password/auth/pwd/new-password.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/BasicClientGroupExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/client_group.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/BasicExternalAuthenticatorWithExternalLogout.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/BasicMultiAuthConfExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/BasicMultiLoginExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/BasicMultipleTestEmailAddressesExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/BasicOneSessionExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/PasswordExpiration.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/BasicResetToStepExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/bcrypt_ssha_migration/pwd_migration.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2/Cas2ExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2_duo/Cas2DuoExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2_duo/Readme.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2_duo/docs/joinded_flows.dia delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2_duo/docs/joinded_flows.jpg delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.dia delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.jpg delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/cert_creds.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/generated_certs.zip delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/ciba/FirebaseEndUserNotification.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/compromised_password.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/Attributes.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/reg.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/register.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/FortinetExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/GooglePlusExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/custom_script_entry.ldif delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/gplus_client_secrets.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/workflow.txt delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/alter_login.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst_login.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/UpdateToken.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/obconnectExternalAuthentication.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/redirect.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidlogin.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidpostlogin.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/Properties description.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/img/gluu_otp_integration_authentication_workflow.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/_remote.repositories delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT-javadoc.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT-sources.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT.pom delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/_remote.repositories delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-javadoc.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-sources.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT.pom delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/_remote.repositories delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/oath-parent-0.0.1-SNAPSHOT.pom delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/maven-metadata-local.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sample/otp_configuration.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sequence_diagram.txt delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/PassportExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/sample/passport_script_entry.ldif delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/phonefactor/pflogin.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/postauthn/postauthn.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/register.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml-passport/SamlPassportAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/Gluu Inbound SAML Design (no Session).png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/SamlExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.jar delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.jar.md5 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.jar.sha1 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.md5 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.sha1 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.md5 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.sha1 delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/sample/super_gluu_creds.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tpauthenticate.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tppair.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/UafExternalAuthenticator.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/gluu_uaf_integration_authentication_workflow.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/oob_qr_code.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/typical_uaf_architecture.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/uaf_device_integration_models.png delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/sequence_diagram.txt delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidlogin.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidregister.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/README.md delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/checkemail.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpass.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpassbind.xhtml delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/static/js/wwpass-frontend.js delete mode 100755 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/ticket.json delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.ca.crt delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.py delete mode 100644 jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpassauth.py diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/Readme.txt b/docs/script-catalog/person_authentication/other/acr_router/Readme.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/Readme.txt rename to docs/script-catalog/person_authentication/other/acr_router/Readme.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/readme.txt b/docs/script-catalog/person_authentication/other/allowed_countries/readme.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/readme.txt rename to docs/script-catalog/person_authentication/other/allowed_countries/readme.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/README.txt b/docs/script-catalog/person_authentication/other/basic.client_group/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/README.txt rename to docs/script-catalog/person_authentication/other/basic.client_group/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/README.txt b/docs/script-catalog/person_authentication/other/basic.external_logout/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/README.txt rename to docs/script-catalog/person_authentication/other/basic.external_logout/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.lock.account/README.txt b/docs/script-catalog/person_authentication/other/basic.lock.account/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.lock.account/README.txt rename to docs/script-catalog/person_authentication/other/basic.lock.account/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/INSTALLATION.txt b/docs/script-catalog/person_authentication/other/basic.multi_auth_conf/INSTALLATION.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/INSTALLATION.txt rename to docs/script-catalog/person_authentication/other/basic.multi_auth_conf/INSTALLATION.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/README.txt b/docs/script-catalog/person_authentication/other/basic.multi_auth_conf/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/README.txt rename to docs/script-catalog/person_authentication/other/basic.multi_auth_conf/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/INSTALLATION.txt b/docs/script-catalog/person_authentication/other/basic.multi_login/INSTALLATION.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/INSTALLATION.txt rename to docs/script-catalog/person_authentication/other/basic.multi_login/INSTALLATION.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/README.txt b/docs/script-catalog/person_authentication/other/basic.multi_login/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/README.txt rename to docs/script-catalog/person_authentication/other/basic.multi_login/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/README.txt b/docs/script-catalog/person_authentication/other/basic.multiple_test_email_addresses/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/README.txt rename to docs/script-catalog/person_authentication/other/basic.multiple_test_email_addresses/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/README.txt b/docs/script-catalog/person_authentication/other/basic.one_session/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/README.txt rename to docs/script-catalog/person_authentication/other/basic.one_session/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/README.txt b/docs/script-catalog/person_authentication/other/basic.reset_to_step/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/README.txt rename to docs/script-catalog/person_authentication/other/basic.reset_to_step/README.txt diff --git a/docs/script-catalog/person_authentication/other/bioid/README.txt b/docs/script-catalog/person_authentication/other/bioid/README.txt new file mode 100644 index 00000000000..6d988c5d079 --- /dev/null +++ b/docs/script-catalog/person_authentication/other/bioid/README.txt @@ -0,0 +1,72 @@ +# BioID Web Service +## Overview +[BioID Web Service](https://www.bioid.com) is a "Biometrics as a service" provider. This document will explain how to use Gluu's [BioID interception script](https://github.com/GluuFederation/oxAuth/blob/master/Server/integrations/bioID/BioIDExternalAuthenticator.py) to configure the Gluu Server for a two-step authentication process with username and password as the first step, and BioID's biometric authentication as the second step. + +In order to use this authentication mechanism your organization will need to register for a BioID account. + +## Prerequisitesm +- A Gluu Server ([installation instructions](../installation-guide/index.md)); +- [BioID interception script](https://github.com/GluuFederation/oxAuth/blob/master/Server/integrations/bioID/BioIDExternalAuthenticator.py) (included in the default Gluu Server distribution); +- An account with [BioID](https://bwsportal.bioid.com/register). + +## Properties +The mandatory properties in the BioID authentication script are as follows +| Property | Description | Example | +|-----------------------|-------------------------------|---------------| +|ENDPOINT |URL of the BioID Web Service|`https://bws.bioid.com/extension/`| +|APP_IDENTIFIER |API key |`c20b04cc-776a-45ed-7a1f-06347f8edf6c`| +|APP_SECRET |API secret |`sTGB4n4HAkvc2BnJp6KeNUTk`| +|STORAGE |The storage name assigned by BioID depending on the type of contract you have. |`bws`| +|PARTITION |A number assigned to your company by BioID. |`12345`| + + + +## Configure BioID Account + +1. [Sign up](https://bwsportal.bioid.com/register) for a BioID account. + +2. Upon registration, you will recieve an email with the instance name (listed as STORAGE in Gluu's BioID authentication script), partition number(listed as PARTITION in Gluu's BioID authentication script). + +3. As the owner of this instance, you are entitled to access BWS Portal at https://bwsportal.bioid.com using the account associated with your email. +With the BWS Portal, you can do the following: +a. View your trial information such as your credentials (e.g. your client certificate), enrolled classes, BWS logs and more. +b. Create your App ID and App secret, under "Web API keys". + +## BioID Documentation + +You can find all API reference at https://developer.bioid.com/bwsreference. +Lots of useful information about BWS is available at https://developer.bioid.com/blog. +If you intend to use liveness detection, you will find information about motion trigger helpful: https://developer.bioid.com/app-developer-guide/bioid-motion-detection + +## Configure oxTrust + +Follow the steps below to configure the BioID module in the oxTrust Admin GUI. + +1. Navigate to `Configuration` > `Person Authentication Scripts`. +1. Scroll down to the BioID authentication script +![bioid-script](../img/admin-guide/multi-factor/bioid-script.png) + +1. Configure the properties, all of which are mandatory, according to your API + +1. Enable the script by ticking the check box +![enable](../img/admin-guide/enable.png) + +Now BioID's biometric authentication is available as an authentication mechanism for your Gluu Server. This means that, using OpenID Connect `acr_values`, applications can now request BioID biometric authentication for users. + +!!! Note + To make sure BioID has been enabled successfully, you can check your Gluu Server's OpenID Connect configuration by navigating to the following URL: `https:///.well-known/openid-configuration`. Find `"acr_values_supported":` and you should see `"bioid"`. + +## Make BioID the Default Authentication Mechanism + +Now applications can request BioID's biometric authentication. To make BioID biometic authentication your default authentication mechanism, follow these instructions: + +1. Navigate to `Configuration` > `Manage Authentication`. +2. Select the `Default Authentication Method` tab. +3. In the Default Authentication Method window you will see two options: `Default acr` and `oxTrust acr`. + + - The `oxTrust acr` field controls the authentication mechanism that is presented to access the oxTrust dashboard GUI (the application you are in). + - The `Default acr` field controls the default authentication mechanism that is presented to users from all applications that leverage your Gluu Server for authentication. + +You can change one or both fields to BioID authentication as you see fit. If you want BioID to be the default authentication mechanism for access to oxTrust and all other applications that leverage your Gluu Server, change both fields to bioid. + +![BioID](../img/admin-guide/multi-factor/bioID.png) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Generate certs guide.md b/docs/script-catalog/person_authentication/other/cert/Generate certs guide.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Generate certs guide.md rename to docs/script-catalog/person_authentication/other/cert/Generate certs guide.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Generate certs without configs.md b/docs/script-catalog/person_authentication/other/cert/Generate certs without configs.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Generate certs without configs.md rename to docs/script-catalog/person_authentication/other/cert/Generate certs without configs.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Quick certs guide for testing.md b/docs/script-catalog/person_authentication/other/cert/Quick certs guide for testing.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/Quick certs guide for testing.md rename to docs/script-catalog/person_authentication/other/cert/Quick certs guide for testing.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/README.txt b/docs/script-catalog/person_authentication/other/cert/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/README.txt rename to docs/script-catalog/person_authentication/other/cert/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/readme.txt b/docs/script-catalog/person_authentication/other/compromised_password/readme.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/readme.txt rename to docs/script-catalog/person_authentication/other/compromised_password/readme.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/duo/README.txt b/docs/script-catalog/person_authentication/other/duo/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/duo/README.txt rename to docs/script-catalog/person_authentication/other/duo/README.txt diff --git a/docs/script-catalog/person_authentication/other/forgot_password/README.md b/docs/script-catalog/person_authentication/other/forgot_password/README.md deleted file mode 100644 index 82fef8bed4a..00000000000 --- a/docs/script-catalog/person_authentication/other/forgot_password/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Forgot Password 2FA Token Interception Script - -## Description - -This script is a 2 in 1. It can be used to enable user to reset its password **or** to enable 2FA sending a token to user's email : - -How they work: - -### Forgot Password -* Step 1: User enters e-mail and if e-mail exists, user receive a token via email -* Step 2: User enters token received by e-mail -* Step 3: User enters new password - -### Emai 2FA -* Step 1: User enters username and password -* Step 2: User enters token received by e-mail - -## Instalation - -* Make sure you have your **SMTP settings correctly Gluu Server** - Navigate to Configuration > Organization Configuration > SMTP Server Configuration -* Set up the script function (Forgot Password or Email 2FA) - Navigate to Configuration > Manage Custom Scripts, choose the script and set a **custom attribute** with key `SCRIPT_FUNCTION` and value `forgot_password` for Forgot Password mode, or `email_2FA` for Email 2FA mode. -* Enable the custom script. - -Please notice the xhtml files for this script are currently located at `oxAuth/Server/src/main/webapp/auth/forgot_password/` - -Note: If you want to use both scripts, you'll need to copy it and change the **custom attribute** from the copied script. diff --git a/docs/script-catalog/person_authentication/other/forgot_password/forgot_password.py b/docs/script-catalog/person_authentication/other/forgot_password/forgot_password.py deleted file mode 100644 index 7a4d3856e47..00000000000 --- a/docs/script-catalog/person_authentication/other/forgot_password/forgot_password.py +++ /dev/null @@ -1,435 +0,0 @@ -# coding: utf-8 -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Christian Eland - - -from org.xdi.oxauth.service import AuthenticationService -from io.jans.as.server.service import UserService -from org.gluu.oxauth.auth import Authenticator -from org.xdi.oxauth.security import Identity -from org.xdi.model.custom.script.type.auth import PersonAuthenticationType -from org.xdi.service.cdi.util import CdiUtil -from org.xdi.util import StringHelper -from org.xdi.oxauth.util import ServerUtil -from io.jans.as.common.service.common import ConfigurationService -from io.jans.as.common.service.common import EncryptionService -from io.jans.jsf2.message import FacesMessages -from jakarta.faces.application import FacesMessage -from io.jans.orm.exception import AuthenticationException - -#dealing with smtp server -import smtplib - -#dealing with emails -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText - -# This one is from core Java -from java.util import Arrays - -# to generate string token -import random -import string - -# regex -import re - -import urllib - -import java - -class EmailValidator(): - ''' - Class to check e-mail format - ''' - regex = '^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$' - - def check(self, email): - ''' - Check if email format is valid - returns: boolean - ''' - - if(re.search(self.regex,email)): - print "Forgot Password - %s is a valid email format" % email - return True - else: - print "Forgot Password - %s is an invalid email format" % email - return False - -class Token: - #class that deals with string token - - def generateToken(self): - ''' method to generate token string - returns: String - ''' - letters = string.ascii_lowercase - - #token lenght - lenght = 20 - - #generate token - token = ''.join(random.choice(letters) for i in range(lenght)) - print "Forgot Password - Generating token" - - return token - - -class EmailSender(): - #class that sends e-mail through smtp - - def getSmtpConfig(self): - ''' - get SMTP config from Gluu Server - return dict - ''' - - smtpconfig = CdiUtil.bean(ConfigurationService).getConfiguration().getSmtpConfiguration() - - if smtpconfig is None: - print "Forgot Password - SMTP CONFIG DOESN'T EXIST - Please configure" - - else: - print "Forgot Password - SMTP CONFIG FOUND" - encryptionService = CdiUtil.bean(EncryptionService) - smtp_config = { - 'host' : smtpconfig.getHost(), - 'port' : smtpconfig.getPort(), - 'user' : smtpconfig.getUserName(), - 'from' : smtpconfig.getFromEmailAddress(), - 'pwd_decrypted' : encryptionService.decrypt(smtpconfig.getPassword()), - 'req_ssl' : smtpconfig.isRequiresSsl(), - 'requires_authentication' : smtpconfig.isRequiresAuthentication(), - 'server_trust' : smtpconfig.isServerTrust() - } - - return smtp_config - - - - def sendEmail(self,useremail,token): - ''' - send token by e-mail to useremail - ''' - - # server connection - smtpconfig = self.getSmtpConfig() - - try: - s = smtplib.SMTP(smtpconfig['host'], port=smtpconfig['port']) - - - if smtpconfig['requires_authentication']: - - if smtpconfig['req_ssl']: - s.starttls() - - s.login(smtpconfig['user'], smtpconfig['pwd_decrypted']) - - - #message setup - msg = MIMEMultipart() #create message - - message = "Here is your token: %s" % token - - msg['From'] = smtpconfig['from'] #sender - msg['To'] = useremail #recipient - msg['Subject'] = "Password Reset Request" #subject - - #attach message body - msg.attach(MIMEText(message, 'plain')) - - #send message via smtp server - # send_message method is for python3 only s.send_message(msg) - - #send email (python2) - s.sendmail(msg['From'],msg['To'],msg.as_string()) - - #after sent, delete - del msg - - except smtplib.SMTPAuthenticationError as err: - print "Forgot Password - SMTPAuthenticationError - %s - %s" % (MY_ADDRESS,PASSWORD) - print err - - except smtplib.smtplib.SMTPSenderRefused as err: - print "Forgot Password - SMTPSenderRefused - " + err - - -class PersonAuthentication(PersonAuthenticationType): - - - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - - print "Forgot Password - Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Forgot Password - Destroyed successfully" - return True - - def getApiVersion(self): - # I'm not sure why is 11 and not 2 - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - ''' - Authenticates user - Step 1 will be defined according to SCRIPT_FUNCTION custom attribute - returns: boolean - ''' - - #gets custom attribute - sf = configurationAttributes.get("SCRIPT_FUNCTION").getValue2() - - print "Forgot Password - %s - Authenticate for step %s" % (sf, step) - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - - if step == 1: - - if sf == "forgot_password": - - - authenticationService = CdiUtil.bean(AuthenticationService) - - logged_in = authenticationService.authenticate(user_name, user_password) - - - if not logged_in: - - - email = ServerUtil.getFirstValue(requestParameters, "ForgotPasswordForm:useremail") - validator = EmailValidator() - if not validator.check(email): - print "Forgot Password - Email format invalid" - return False - - else: - print "Forgot Password -Email format valid" - - print "Forgot Password - Entered email is %s" % email - identity.setWorkingParameter("useremail",email) - - # Just trying to get the user by the email - user_service = CdiUtil.bean(UserService) - user2 = user_service.getUserByAttribute("mail", email) - - if user2 is not None: - - print user2 - print "Forgot Password - User with e-mail %s found." % user2.getAttribute("mail") - - # send email - new_token = Token() - token = new_token.generateToken() - sender = EmailSender() - print "Email: " + email - print "Token: " + token - sender.sendEmail(email,token) - - - identity.setWorkingParameter("token", token) - print identity.getWorkingParameter("token") - - - - else: - print "Forgot Password - User with e-mail %s not found" % email - - return True - - - else: - # if user is already authenticated, returns true. - - user = authenticationService.getAuthenticatedUser() - print "Forgot Password - User %s is authenticated" % user.getUserId() - - return True - - if sf == "email_2FA": - - try: - # Just trying to get the user by the uid - authenticationService = CdiUtil.bean(AuthenticationService) - logged_in = authenticationService.authenticate(user_name, user_password) - - print 'email_2FA user_name: ' + str(user_name) - - user_service = CdiUtil.bean(UserService) - user2 = user_service.getUserByAttribute("uid", user_name) - - if user2 is not None: - print "user:" - print user2 - print "Forgot Password - User with e-mail %s found." % user2.getAttribute("mail") - email = user2.getAttribute("mail") - uid = user2.getAttribute("uid") - - # send token - # send email - new_token = Token() - token = new_token.generateToken() - sender = EmailSender() - print "Email: " + email - print "Token: " + token - sender.sendEmail(email,token) - - identity.setWorkingParameter("token", token) - - return True - - except AuthenticationException as err: - print err - return False - - - - - if step == 2: - # step 2 user enters token - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - authenticationService = CdiUtil.bean(AuthenticationService) - logged_in = authenticationService.authenticate(user_name, user_password) - - # retrieves token typed by user - input_token = ServerUtil.getFirstValue(requestParameters, "ResetTokenForm:inputToken") - - print "Forgot Password - Token inputed by user is %s" % input_token - - token = identity.getWorkingParameter("token") - print "Forgot Password - Retrieved token" - email = identity.getWorkingParameter("useremail") - print "Forgot Password - Retrieved email" - - # compares token sent and token entered by user - if input_token == token: - print "Forgot Password - token entered correctly" - identity.setWorkingParameter("token_valid", True) - - return True - - else: - print "Forgot Password - wrong token" - return False - - - if step == 3: - # step 3 enters new password (only runs if custom attibute is forgot_password - - user_service = CdiUtil.bean(UserService) - - email = identity.getWorkingParameter("useremail") - user2 = user_service.getUserByAttribute("mail", email) - - - user_name = user2.getUserId() - - new_password = ServerUtil.getFirstValue(requestParameters, "UpdatePasswordForm:newPassword") - - print "Forgot Password - New password submited" - - # update user info with new password - user2.setAttribute("userPassword",new_password) - print "Forgot Password - user uid is %s" % user_name - print "Forgot Password - Updating user with new password..." - user_service.updateUser(user2) - print "Forgot Password - User updated with new password" - # authenticates and login user - print "Forgot Password - Loading authentication service..." - authenticationService2 = CdiUtil.bean(AuthenticationService) - - print "Forgot Password - Trying to authenticate user..." - login = authenticationService2.authenticate(user_name, new_password) - - return True - - def prepareForStep(self, configurationAttributes, requestParameters, step): - - print "Forgot Password - Preparing for step %s" % step - - return True - - - # Return value is a java.util.List - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("token","useremail","token_valid") - - - # This method determines how many steps the authentication flow may have - # It doesn't have to be a constant value - def getCountAuthenticationSteps(self, configurationAttributes): - - sf = configurationAttributes.get("SCRIPT_FUNCTION").getValue2() - - - # if option is forgot_token - if sf == "forgot_password": - print "Entered sf == forgot_password" - return 3 - - # if ption is email_2FA - if sf == "email_2FA": - print "Entered if sf=email_2FA" - return 2 - - else: - print "Forgot Password - Custom Script Custom Property Incorrect, please check" - - - # The xhtml page to render upon each step of the flow - # returns a string relative to oxAuth webapp root - def getPageForStep(self, configurationAttributes, step): - - sf = configurationAttributes.get("SCRIPT_FUNCTION").getValue2() - - if step == 1: - - if sf == "forgot_password": - return "/auth/forgot_password/forgot.xhtml" - - if sf == 'email_2FA': - return "" - - if step == 2: - return "/auth/forgot_password/entertoken.xhtml" - - if step == 3: - if sf == "forgot_password": - return "/auth/forgot_password/newpassword.xhtml" - - - def getNextStep(self, configurationAttributes, requestParameters, step): - # Method used on version 2 (11?) - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/README.txt b/docs/script-catalog/person_authentication/other/fortinet/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/README.txt rename to docs/script-catalog/person_authentication/other/fortinet/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/README.txt b/docs/script-catalog/person_authentication/other/gplus/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/README.txt rename to docs/script-catalog/person_authentication/other/gplus/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/README_idfirst.md b/docs/script-catalog/person_authentication/other/idfirst/README_idfirst.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/README_idfirst.md rename to docs/script-catalog/person_authentication/other/idfirst/README_idfirst.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/documentation/README.txt b/docs/script-catalog/person_authentication/other/obconnect/documentation/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/documentation/README.txt rename to docs/script-catalog/person_authentication/other/obconnect/documentation/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/documentation/larger_picture.png b/docs/script-catalog/person_authentication/other/obconnect/documentation/larger_picture.png similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/documentation/larger_picture.png rename to docs/script-catalog/person_authentication/other/obconnect/documentation/larger_picture.png diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/read.txt b/docs/script-catalog/person_authentication/other/registration/read.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/read.txt rename to docs/script-catalog/person_authentication/other/registration/read.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/INSTALLATION.txt b/docs/script-catalog/person_authentication/other/saml/INSTALLATION.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/INSTALLATION.txt rename to docs/script-catalog/person_authentication/other/saml/INSTALLATION.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/README.txt b/docs/script-catalog/person_authentication/other/saml/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/README.txt rename to docs/script-catalog/person_authentication/other/saml/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/twilio_sms/README.txt b/docs/script-catalog/person_authentication/other/twilio_sms/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/twilio_sms/README.txt rename to docs/script-catalog/person_authentication/other/twilio_sms/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/Properties description.md b/docs/script-catalog/person_authentication/other/uaf/Properties description.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/Properties description.md rename to docs/script-catalog/person_authentication/other/uaf/Properties description.md diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/INSTALLATION.md b/docs/script-catalog/person_authentication/other/wwpass/INSTALLATION.md similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/INSTALLATION.md rename to docs/script-catalog/person_authentication/other/wwpass/INSTALLATION.md diff --git a/docs/script-catalog/person_authentication/other/wwpass/README.md b/docs/script-catalog/person_authentication/other/wwpass/README.md index 59e1f770fe4..62b46b60745 100644 --- a/docs/script-catalog/person_authentication/other/wwpass/README.md +++ b/docs/script-catalog/person_authentication/other/wwpass/README.md @@ -1,6 +1,4 @@ -# Setting Up WWPass Authentication in Gluu Server - -## Introduction +# WWPass integration for Gluu [WWPass](https://wwpass.com/) replaces the traditional username and password login with a more advanced multi-factor authentication solution. WWPass employs @@ -10,235 +8,12 @@ starts with a smartphone app or a hardware token as the first authentication factor. Then additional authentication factors such as PIN or biometrics can be added to verify the user identity further. -[Gluu Server](https://gluu.org/docs/gluu-server/4.1/) is a container -distribution of free open source software (FOSS) for identity and access -management (IAM). Gluu Server combines SAML 2.0, LDAP, OpenID Connect, -and other authentication and authorization protocol implementations to create -a platform for user authentication, identity information, and policy decisions. - -Combining WWPass strong multi-factor authentication with the versatility of -Gluu Server helps to build secure IAM solutions that can be used for single -sign-on (SSO), customer identity and access management (CIAM), and identity -federation. - -## Prerequisites - -This tutorial assumes that you have the following: - -- Gluu Server 4.1.1 installed on Ubuntu Server 18.04 or 16.04; -- An administrative account on this Ubuntu Server; -- An application certificate and private key for WWPass authentication; -- WWPass Key app or hardware token; - -### Obtain Application Certificate and Private Key From WWPass - -To obtain an application certificate and private key go to -[wwpass.com](https://wwpass.com), click **Sign Up** to create a developer -account or **Log In** if you already have an account. Then follow the website -instructions to register your application domain and issue the application -certificate. - -## Prepare WWPass Integration Files - -Copy this directory to your Gluu server and make it current -```console -cd wwpass -``` - -Files in `pages` directory should be deployed to -`/opt/gluu-server/opt/gluu/jetty/oxauth/custom/pages/` - -```console -sudo cp -rL pages/* /opt/gluu-server/opt/gluu/jetty/oxauth/custom/pages/ -``` - -Files in `static` directory should be deployed to -`/opt/gluu-server/opt/gluu/jetty/oxauth/custom/static/` - -```console -sudo cp -rL pages/* /opt/gluu-server/opt/gluu/jetty/oxauth/custom/static/ -``` - -Copy `wwpass.py` to `/opt/gluu-server/opt/gluu/python/libs/` - -```console -sudo cp wwpass.py /opt/gluu-server/opt/gluu/python/libs/ -``` - -Copy `ticket.json` to `/opt/gluu-server/opt/wwpass_gluu/cgi` - -``` console -sudo mkdir -p /opt/gluu-server/opt/wwpass_gluu/cgi -sudo cp ticket.json /opt/gluu-server/opt/wwpass_gluu/cgi -``` - -Make sure `ticket.json` is executable - -```console -sudo chmod 755 /opt/gluu-server/opt/wwpass_gluu/cgi/ticket.json -``` - -Copy WWPass application certificate and private key to -`/opt/gluu-server/opt/wwpass_gluu/` -(assuming the certificate and key files are in your home directory) - -```console -sudo cp ~/gluu_client.crt /opt/gluu-server/opt/wwpass_gluu/gluu_client.crt -sudo cp ~/gluu_client.key /opt/gluu-server/opt/wwpass_gluu/gluu_client.key -``` - -Replace `~/gluu_client.crt` and `~/gluu_client.key` with the names and location -of your certificate and key files. - -Copy WWPass CA certificate `wwpass.ca.crt` to `/opt/gluu-server/opt/wwpass_gluu/` - -```console -sudo cp wwpass.ca.crt /opt/gluu-server/opt/wwpass_gluu -``` - -Log in to the Gluu Server container - -```console -sudo /sbin/gluu-serverd login -``` - -Change ownership of files and directories just copied - -```console -chown -R jetty:jetty /opt/jetty -chown root:gluu /opt/gluu/python/libs/wwpass.py -``` - -## Configure Apache - -Use your favorite console text editor to change Apache configuration - -```console -[vi|nano|joe|...] /opt/gluu-server/etc/apache2/sites-available/https_gluu.conf -``` - -Scroll down the file until you find the last `...` tag and -insert the following snippet below it: - -```apache - - require all granted - - -ScriptAlias "/wwpass/" "/opt/wwpass_gluu/cgi/" - - - SetHandler cgi-script - Options +ExecCGI - Order deny,allow - Allow from all - -``` - -Save the file and exit the editor. - -Enable mod_cgi and restart apache: - -```console -a2enmod cgi -systemctl restart apache2 -``` - -Check that `ticket.json` is working. -Go to `https:///wwpass/ticket.json`. -If your setup is correct, you will see output like this: - -```json -{"result": true, "data": "SPNAME:07629a1963c5e4f4f339ecb852b7a0bf10a90c62@p-sp-05-50:16033", "ttl": 600, "encoding": "plain"} -``` - -## Configure Gluu Server - -Log in as administrator and go to "Configuration -> Manage Custom scripts". - -In `Person Authentication` tab, click `Add custom script configuration` at the bottom of the page - -Create custom script `wwpass` with Location Type set to `Database`. - -Add the following to `Custom Property` fields by clicking on `Add new property` button: - -- wwpass_crt_file: /opt/wwpass_gluu/gluu_client.crt -- wwpass_key_file: /opt/wwpass_gluu/gluu_client.key -- registration_url: URL of the registration web application, if you have one. Do not add this property otherwise -- recovery_url: URL for account recovery, if you have one. Do not add this property otherwise. - -To require PIN or biometrics during login, add: - -- use_pin: True - -To enable binding WWPass keys with email, add: - -- allow_email_bind: True - -Note, your Gluu server should be able to send emails, see -`Configuration -> Organization configuration -> SMTP Server Configuration`. - -To enable binding WWPass keys with existing usernames and passwords, add: - -- allow_password_bind: True - -To enable binding WWPass keys with another WWPass key, add: - -- allow_passkey_bind: True - -Replace the content of `Script` textbox with the content of `wwpassauth.py` from `gluu-master` - -Set `Enabled` checkbox to enable the custom script: - -Click the `Update` button. - -It's also recommended to increase the unauthenticated session lifetime to give -users more time to bind their WWPass keys. - -Go to `Configuration -> JSON configuration -> OxAuth Configuration`, find -`sessionIdUnauthenticatedUnusedLifetime` setting and set it to `600` or more. - -Click `Update` to save settings. - -### Set up Authentication Method - -Before switching to WWPass authentication, make sure you have opened -an administrator session in a different browser (not in a different window, -but a completely different browser). Do not close that browser window and -reload it from time to time to make sure your session does not expire. - -Keep the backup session opened until you are sure that WWPass authentication -works properly or you might lock yourself out of Gluu. If that happens, refer to: -[Gluu FAQ](https://gluu.org/docs/gluu-server/operation/faq/#revert-an-authentication-method) - -In the Gluu Admin interface, navigate to `Configuration -> Manage Authentication -> Default Authentication Method`. -Set both options to "wwpass". - -Click `Update` to save settings. - -### Test Your Setup - -Open "https:///" in a different browser (not the one you used to -configure Gluu). - -Try to sign in to your Gluu server with WWPass and bind your key using either -email or username and password. - -If something does not work as expected, return to your main browser and revert -`Configuration -> Manage Authentication -> Default Authentication Method` back -to `auth_ldap_server` while you troubleshoot the problem. - -## Troubleshooting +## Installation -Relevant Gluu log files are: +To install WWPass support in Gluu server refer to [INSTALLATION.md](INSTALLATION.md). -- `/opt/gluu-server/opt/gluu/jetty/oxauth/logs/oxauth.log` -- `/opt/gluu-server/opt/gluu/jetty/oxauth/logs/oxauth_script.log` +To install additional components refer to main wwpass-gluu repository at https://github.com/wwpass/gluu -Check the files above for any errors. Errors in `wwpass` interception script -are also displayed in Gluu web interface at 'Configuration -> Manage Custom -scripts'. If there are any errors in the script, its name will be in red and -the script editor will display the red button named "Show Error". +## Contacts -Feel free to contact WWPass at support@wwpass.com if you have troubles -integrating WWPass in your Gluu Server. +Feel free to contact WWPass at support@wwpass.com if you have trouble integrating WWPass in your Gluu setup \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/yubicloud/README.txt b/docs/script-catalog/person_authentication/other/yubicloud/README.txt similarity index 100% rename from jans-linux-setup/jans_setup/static/extension/person_authentication/other/yubicloud/README.txt rename to docs/script-catalog/person_authentication/other/yubicloud/README.txt diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/README.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/README.md deleted file mode 100644 index ef38c90e805..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# 2FA authentication scripts - -Jython files contained in the top level of this folder are already added as authentication scripts in your Janssen installation. - -Inside `other` directory you may find extra information about these scripts as well as additional (non curated) scripts that you may use as a guide to integrate third party authentication services or APIs with Janssen server. \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/acr_routerauthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/acr_routerauthenticator.py deleted file mode 100644 index 74526837884..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/acr_router/acr_routerauthenticator.py +++ /dev/null @@ -1,84 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# -from __future__ import print_function -from io.jans.model.custom.script.type.auth import PersonAuthenticationType - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - """ - Args: - currentTimeMillis (int): current time in miliseconds - """ - self.currentTimeMillis = currentTimeMillis - - @classmethod - def init(cls, customScript, configurationAttributes): - print("ACR Router. Initialization") - if not configurationAttributes.containsKey("new_acr_value"): - print("ACR Router. Initialization. Property acr_router_value is mandatory") - return False - print("ACR Router. Initialized successfully") - return True - - @classmethod - def destroy(cls, configurationAttributes): - print("ACR Router. Destroy") - print("ACR Router. Destroyed successfully") - - return True - - @classmethod - def getAuthenticationMethodClaims(cls, requestParameters): - return None - - @classmethod - def getApiVersion(cls): - return 11 - - @classmethod - def isValidAuthenticationMethod(cls, usageType, configurationAttributes): - return False - - @classmethod - def getAlternativeAuthenticationMethod(cls, usageType, configurationAttributes): - print("ACR Router. get new acr value") - new_acr_value = configurationAttributes.get("new_acr_value").getValue2() - # Put your custom logic to determine if routing required here... - return new_acr_value - - @classmethod - def authenticate(cls, configurationAttributes, requestParameters, step): - return False - - @classmethod - def prepareForStep(cls, configurationAttributes, requestParameters, step): - return True - - @classmethod - def getExtraParametersForStep(cls, configurationAttributes, step): - return None - - @classmethod - def getCountAuthenticationSteps(cls, configurationAttributes): - return 1 - - @classmethod - def getPageForStep(cls, configurationAttributes, step): - return "" - - @classmethod - def getNextStep(cls, configurationAttributes, requestParameters, step): - return -1 - - @classmethod - def getLogoutExternalUrl(cls, configurationAttributes, requestParameters): - print("Get external logout URL call") - return None - - @classmethod - def logout(cls, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/allowed_countries.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/allowed_countries.py deleted file mode 100644 index cc9779d3fef..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/allowed_countries/allowed_countries.py +++ /dev/null @@ -1,155 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from java.util import Arrays -from org.apache.http.params import CoreConnectionPNames -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from org.gluu.oxauth.model.config import ConfigurationFactory -from io.jans.as.server.service import UserService, AuthenticationService, SessionIdService -from io.jans.as.server.service.net import HttpService -from io.jans.as.server.util import ServerUtil -from io.jans.util import StringHelper -from io.jans.as.server.service.common import EncryptionService -from java.util import Arrays, HashMap, IdentityHashMap - -import java -import datetime -import urllib - -import sys -import json - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic. Initialization" - self.allowedCountries = configurationAttributes.get("allowed_countries").getValue2() - print "Basic. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic. Destroy" - print "Basic. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - session_attributes = identity.getSessionId().getSessionAttributes() - authenticationService = CdiUtil.bean(AuthenticationService) - allowedCountriesListArray = StringHelper.split(self.allowedCountries, ",") - if (len(allowedCountriesListArray) > 0 and session_attributes.containsKey("remote_ip")): - remote_ip = session_attributes.get("remote_ip") - remote_loc_dic = self.determineGeolocationData(remote_ip) - if remote_loc_dic == None: - print "Super-Gluu. Prepare for step 2. Failed to determine remote location by remote IP '%s'" % remote_ip - return - remote_loc = "%s" % ( remote_loc_dic['countryCode']) - print "Your remote location is "+remote_loc - if remote_loc in allowedCountriesListArray: - print "you are allowed to access" - else: - return False - - - if (step == 1): - print "Basic. Authenticate for step 1" - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - logged_in = authenticationService.authenticate(user_name, user_password) - - if (not logged_in): - return False - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def logout(self, configurationAttributes, requestParameters): - return True - - def determineGeolocationData(self, remote_ip): - print "Super-Gluu. Determine remote location. remote_ip: '%s'" % remote_ip - httpService = CdiUtil.bean(HttpService) - http_client = httpService.getHttpsClient() - http_client_params = http_client.getParams() - http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15 * 1000) - geolocation_service_url = "http://ip-api.com/json/%s?fields=520191" % remote_ip - geolocation_service_headers = { "Accept" : "application/json" } - try: - http_service_response = httpService.executeGet(http_client, geolocation_service_url, geolocation_service_headers) - http_response = http_service_response.getHttpResponse() - except: - print "Super-Gluu. Determine remote location. Exception: ", sys.exc_info()[1] - return None - - try: - if not httpService.isResponseStastusCodeOk(http_response): - print "Super-Gluu. Determine remote location. Get invalid response from validation server: ", str(http_response.getStatusLine().getStatusCode()) - httpService.consume(http_response) - return None - response_bytes = httpService.getResponseContent(http_response) - response_string = httpService.convertEntityToString(response_bytes) - httpService.consume(http_response) - finally: - http_service_response.closeConnection() - - if response_string == None: - print "Super-Gluu. Determine remote location. Get empty response from location server" - return None - - - response = json.loads(response_string) - - if not StringHelper.equalsIgnoreCase(response['status'], "success"): - print "Super-Gluu. Determine remote location. Get response with status: '%s'" % response['status'] - return None - - return response - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/ConsentGatheringSample.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/ConsentGatheringSample.py deleted file mode 100644 index ac228de387f..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/ConsentGatheringSample.py +++ /dev/null @@ -1,87 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.authz import ConsentGatheringType -from io.jans.util import StringHelper - -import java -import random - -class ConsentGathering(ConsentGatheringType): - - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Consent-Gathering. Initializing ..." - print "Consent-Gathering. Initialized successfully" - - return True - - def destroy(self, configurationAttributes): - print "Consent-Gathering. Destroying ..." - print "Consent-Gathering. Destroyed successfully" - - return True - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def getApiVersion(self): - return 11 - - # Main consent-gather method. Must return True (if gathering performed successfully) or False (if fail). - # All user entered values can be access via Map context.getPageAttributes() - def authorize(self, step, context): # context is reference of io.jans.as.server.service.external.context.ConsentGatheringContext - print "Consent-Gathering. Authorizing..." - - if step == 1: - allowButton = context.getRequestParameters().get("authorizeForm:allowButton") - if (allowButton != None) and (len(allowButton) > 0): - print "Consent-Gathering. Authorization success for step 1" - return True - - print "Consent-Gathering. Authorization declined for step 1" - elif step == 2: - allowButton = context.getRequestParameters().get("authorizeForm:allowButton") - if (allowButton != None) and (len(allowButton) > 0): - print "Consent-Gathering. Authorization success for step 2" - return True - - print "Consent-Gathering. Authorization declined for step 2" - - return False - - def getNextStep(self, step, context): - return -1 - - def prepareForStep(self, step, context): - if not context.isAuthenticated(): - print "User is not authenticated. Aborting authorization flow ..." - return False - - if step == 2: - pageAttributes = context.getPageAttributes() - - # Generate random consent gathering request - consentRequest = "Requested transaction #%s approval for the amount of sum $ %s.00" % ( random.randint(100000, 1000000), random.randint(1, 100) ) - pageAttributes.put("consent_request", consentRequest) - return True - - return True - - def getStepsCount(self, context): - return 2 - - def getPageForStep(self, step, context): - if step == 1: - return "/authz/authorize.xhtml" - elif step == 2: - return "/authz/transaction.xhtml" - - return "" diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/docs/Authz design.dia b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/authz/docs/Authz design.dia deleted file mode 100644 index 66b1837de3299dfdd5f1c4237c26938f79acb45d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4879 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 - - - - - - oxAuth - New Password - - - - - - -
-
- - - - - -
-
- -
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/BasicClientGroupExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/BasicClientGroupExternalAuthenticator.py deleted file mode 100644 index 6a4eda34261..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/BasicClientGroupExternalAuthenticator.py +++ /dev/null @@ -1,177 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService, AppInitializer -from io.jans.util import StringHelper -from java.util import Arrays, HashMap - -import java -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (client group). Initialization" - - self.allow_default_login = False - if configurationAttributes.containsKey("allow_default_login"): - self.allow_default_login = StringHelper.toBoolean(configurationAttributes.get("allow_default_login").getValue2(), False) - - if not configurationAttributes.containsKey("configuration_file"): - print "Basic (client group). The property configuration_file is empty" - return False - - configurationFilePath = configurationAttributes.get("configuration_file").getValue2() - self.client_configurations = self.loadClientConfigurations(configurationFilePath) - if self.client_configurations == None: - print "Basic (client group). File with client configuration should be not empty" - return False - - print "Basic (client group). Initialized successfully" - return True - - def destroy(self, clientConfiguration): - print "Basic (client group). Destroy" - - print "Basic (client group). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - -def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - session_attributes = identity.getSessionId().getSessionAttributes() - - client_id = session_attributes.get("client_id") - print "Basic (client group). Get client_id: '%s' authorization request" % client_id - - user_groups = self.client_configurations.get(client_id) - if user_groups == None: - print "Basic (client group). There is no user groups configuration for client_id '%s'. allow_default_login: %s" % (client_id, self.allow_default_login) - if not self.allow_default_login: - return False - - result = self.authenticateImpl(credentials, authenticationService) - return result - - is_member_client_groups = self.isUserMemberOfGroups(credentials, user_groups) - if not is_member_client_groups: - print "Basic (client group). User '%s' hasn't permissions to log into client_id '%s' application. " % (credentials.getUsername(), client_id) - return False - - result = self.authenticateImpl(credentials, authenticationService) - return result - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "Basic (client group). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def logout(self, configurationAttributes, requestParameters): - return True - - def authenticateImpl(self, credentials, authenticationService): - print "Basic (client group). Processing user name/password authentication" - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - logged_in = authenticationService.authenticate(user_name, user_password) - - if not logged_in: - return False - - return True - - def loadClientConfigurations(self, configurationFile): - clientConfiguration = None - - # Load configuration from file - f = open(configurationFile, 'r') - try: - configurationFileJson = json.loads(f.read()) - except: - print "Basic (client group). Load configuration from file. Failed to load authentication configuration from file:", configurationFile - return None - finally: - f.close() - - clientConfigurations = HashMap() - for client_key in configurationFileJson.keys(): - client_config = configurationFileJson[client_key] - - client_inum = client_config["client_inum"] - user_groups_array = client_config["user_group"] - user_groups = Arrays.asList(user_groups_array) - clientConfigurations.put(client_inum, user_groups) - - print "Basic (client group). Load configuration from file. Loaded '%s' configurations" % clientConfigurations.size() - print clientConfigurations - - return clientConfigurations - - def isUserMemberOfGroups(self, credentials, groups): - userService = CdiUtil.bean(UserService) - - user_name = credentials.getUsername() - if StringHelper.isEmptyString(user_name): - return False - - find_user_by_uid = userService.getUser(user_name) - - is_member = False - member_of_list = find_user_by_uid.getAttributeValues("memberOf") - if member_of_list == None: - return is_member - - print member_of_list - print groups - - for member_of in member_of_list: - for group in groups: - if StringHelper.equalsIgnoreCase(group, member_of) or member_of.endswith(group): - is_member = True - break - - return is_member - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/client_group.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/client_group.json deleted file mode 100644 index 4476826fc46..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.client_group/client_group.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "client_1":{ - "client_inum":"client_inum_1", - "user_group":[ - "group_dn_1", - "group_dn_2" - ] - }, - "client_2":{ - "client_inum":"client_inum_2", - "user_group":[ - "group_dn_1", - "group_dn_2" - ] - } -} diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/BasicExternalAuthenticatorWithExternalLogout.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/BasicExternalAuthenticatorWithExternalLogout.py deleted file mode 100644 index 94e101a71c9..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.external_logout/BasicExternalAuthenticatorWithExternalLogout.py +++ /dev/null @@ -1,91 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.util import StringHelper - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (with external logout). Initialization" - print "Basic (with external logout). Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic (with external logout). Destroy" - print "Basic (with external logout). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Basic (with external logout). Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - logged_in = authenticationService.authenticate(user_name, user_password) - - if (not logged_in): - return False - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic (with external logout). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Basic (with external logout). Get external logout URL call" - return "https://www.dummy.org/app/logout.htm" - - # In order to get this method call RP should end_session request to https:///oxauth/logout.htm enpoint - # instead of https:///oxauth/restv1/end_session endpoint - def logout(self, configurationAttributes, requestParameters): - print "Basic (with external logout). Logout call" - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/BasicMultiAuthConfExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/BasicMultiAuthConfExternalAuthenticator.py deleted file mode 100644 index 56c0b26fde8..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_auth_conf/BasicMultiAuthConfExternalAuthenticator.py +++ /dev/null @@ -1,293 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService, AppInitializer -from io.jans.as.server.service import MetricService -from io.jans.as.server.service.common import EncryptionService -from io.jans.model.metric import MetricType -from io.jans.util import StringHelper -from io.jans.util import ArrayHelper -from io.jans.orm.service import PersistanceFactoryService -from io.jans.orm.ldap.impl import LdapEntryManagerFactory -from io.jans.model.ldap import GluuLdapConfiguration -from java.util import Arrays, Properties - -import java -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (multi auth conf). Initialization" - - if (not configurationAttributes.containsKey("auth_configuration_file")): - print "Basic (multi auth conf). The property auth_configuration_file is empty" - return False - - authConfigurationFile = configurationAttributes.get("auth_configuration_file").getValue2() - authConfiguration = self.loadAuthConfiguration(authConfigurationFile) - if (authConfiguration == None): - print "Basic (multi auth conf). File with authentication configuration should be not empty" - return False - - validationResult = self.validateAuthConfiguration(authConfiguration) - if (not validationResult): - return False - - ldapExtendedEntryManagers = self.createLdapExtendedEntryManagers(authConfiguration) - if (ldapExtendedEntryManagers == None): - return False - - self.ldapExtendedEntryManagers = ldapExtendedEntryManagers - - print "Basic (multi auth conf). Initialized successfully" - return True - - def destroy(self, authConfiguration): - print "Basic (multi auth conf). Destroy" - - result = True - for ldapExtendedEntryManager in self.ldapExtendedEntryManagers: - ldapConfiguration = ldapExtendedEntryManager["ldapConfiguration"] - ldapEntryManager = ldapExtendedEntryManager["ldapEntryManager"] - - destoryResult = ldapEntryManager.destroy() - result = result and destoryResult - print "Basic (multi auth conf). Destroyed: " + ldapConfiguration.getConfigId() + ". Result: " + str(destoryResult) - - print "Basic (multi auth conf). Destroyed successfully" - - return result - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Basic (multi auth conf). Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - metricService = CdiUtil.bean(MetricService) - timerContext = metricService.getTimer(MetricType.USER_AUTHENTICATION_RATE).time() - try: - keyValue = credentials.getUsername() - userPassword = credentials.getPassword() - - if (StringHelper.isNotEmptyString(keyValue) and StringHelper.isNotEmptyString(userPassword)): - for ldapExtendedEntryManager in self.ldapExtendedEntryManagers: - ldapConfiguration = ldapExtendedEntryManager["ldapConfiguration"] - ldapEntryManager = ldapExtendedEntryManager["ldapEntryManager"] - loginAttributes = ldapExtendedEntryManager["loginAttributes"] - localLoginAttributes = ldapExtendedEntryManager["localLoginAttributes"] - - print "Basic (multi auth conf). Authenticate for step 1. Using configuration: " + ldapConfiguration.getConfigId() - - idx = 0 - count = len(loginAttributes) - while (idx < count): - primaryKey = loginAttributes[idx] - localPrimaryKey = localLoginAttributes[idx] - - loggedIn = authenticationService.authenticate(ldapConfiguration, ldapEntryManager, keyValue, userPassword, primaryKey, localPrimaryKey) - if (loggedIn): - metricService.incCounter(MetricType.USER_AUTHENTICATION_SUCCESS) - return True - idx += 1 - finally: - timerContext.stop() - - metricService.incCounter(MetricType.USER_AUTHENTICATION_FAILURES) - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic (multi auth conf). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def loadAuthConfiguration(self, authConfigurationFile): - authConfiguration = None - - # Load authentication configuration from file - f = open(authConfigurationFile, 'r') - try: - authConfiguration = json.loads(f.read()) - except: - print "Basic (multi auth conf). Load auth configuration. Failed to load authentication configuration from file:", authConfigurationFile - return None - finally: - f.close() - - return authConfiguration - - def validateAuthConfiguration(self, authConfiguration): - isValid = True - - if (not ("ldap_configuration" in authConfiguration)): - print "Basic (multi auth conf). Validate auth configuration. There is no ldap_configuration section in configuration" - return False - - idx = 1 - for ldapConfiguration in authConfiguration["ldap_configuration"]: - if (not self.containsAttributeString(ldapConfiguration, "configId")): - print "Basic (multi auth conf). Validate auth configuration. There is no 'configId' attribute in ldap_configuration section #" + str(idx) - return False - - configId = ldapConfiguration["configId"] - - if (not self.containsAttributeArray(ldapConfiguration, "servers")): - print "Basic (multi auth conf). Validate auth configuration. Property 'servers' in configuration '" + configId + "' is invalid" - return False - - if (self.containsAttributeString(ldapConfiguration, "bindDN")): - if (not self.containsAttributeString(ldapConfiguration, "bindPassword")): - print "Basic (multi auth conf). Validate auth configuration. Property 'bindPassword' in configuration '" + configId + "' is invalid" - return False - - if (not self.containsAttributeString(ldapConfiguration, "useSSL")): - print "Basic (multi auth conf). Validate auth configuration. Property 'useSSL' in configuration '" + configId + "' is invalid" - return False - - if (not self.containsAttributeString(ldapConfiguration, "maxConnections")): - print "Basic (multi auth conf). Validate auth configuration. Property 'maxConnections' in configuration '" + configId + "' is invalid" - return False - - if (not self.containsAttributeArray(ldapConfiguration, "baseDNs")): - print "Basic (multi auth conf). Validate auth configuration. Property 'baseDNs' in configuration '" + configId + "' is invalid" - return False - - if (not self.containsAttributeArray(ldapConfiguration, "loginAttributes")): - print "Basic (multi auth conf). Validate auth configuration. Property 'loginAttributes' in configuration '" + configId + "' is invalid" - return False - - if (not self.containsAttributeArray(ldapConfiguration, "localLoginAttributes")): - print "Basic (multi auth conf). Validate auth configuration. Property 'localLoginAttributes' in configuration '" + configId + "' is invalid" - return False - - if (len(ldapConfiguration["loginAttributes"]) != len(ldapConfiguration["localLoginAttributes"])): - print "Basic (multi auth conf). Validate auth configuration. The number of attributes in 'loginAttributes' and 'localLoginAttributes' isn't equal in configuration '" + configId + "'" - return False - - idx += 1 - - return True - - def createLdapExtendedEntryManagers(self, authConfiguration): - ldapExtendedConfigurations = self.createLdapExtendedConfigurations(authConfiguration) - - appInitializer = CdiUtil.bean(AppInitializer) - persistanceFactoryService = CdiUtil.bean(PersistanceFactoryService) - ldapEntryManagerFactory = persistanceFactoryService.getPersistenceEntryManagerFactory(LdapEntryManagerFactory) - persistenceType = ldapEntryManagerFactory.getPersistenceType() - - ldapExtendedEntryManagers = [] - for ldapExtendedConfiguration in ldapExtendedConfigurations: - connectionConfiguration = ldapExtendedConfiguration["connectionConfiguration"] - ldapConfiguration = ldapExtendedConfiguration["ldapConfiguration"] - - ldapProperties = Properties() - for key, value in connectionConfiguration.items(): - value_string = value - if isinstance(value_string, list): - value_string = ", ".join(value) - else: - value_string = str(value) - - ldapProperties.setProperty(persistenceType + "." + key, value_string) - - if StringHelper.isNotEmptyString(ldapConfiguration.getBindPassword()): - ldapProperties.setProperty(persistenceType + ".bindPassword", ldapConfiguration.getBindPassword()) - - ldapEntryManager = ldapEntryManagerFactory.createEntryManager(ldapProperties) - - ldapExtendedEntryManagers.append({ "ldapConfiguration" : ldapConfiguration, "ldapProperties" : ldapProperties, "loginAttributes" : ldapExtendedConfiguration["loginAttributes"], "localLoginAttributes" : ldapExtendedConfiguration["localLoginAttributes"], "ldapEntryManager" : ldapEntryManager }) - - return ldapExtendedEntryManagers - - def createLdapExtendedConfigurations(self, authConfiguration): - ldapExtendedConfigurations = [] - - for connectionConfiguration in authConfiguration["ldap_configuration"]: - configId = connectionConfiguration["configId"] - - servers = connectionConfiguration["servers"] - - bindDN = None - bindPassword = None - useAnonymousBind = True - if (self.containsAttributeString(connectionConfiguration, "bindDN")): - useAnonymousBind = False - bindDN = connectionConfiguration["bindDN"] - bindPassword = CdiUtil.bean(EncryptionService).decrypt(connectionConfiguration["bindPassword"]) - - useSSL = connectionConfiguration["useSSL"] - maxConnections = connectionConfiguration["maxConnections"] - baseDNs = connectionConfiguration["baseDNs"] - loginAttributes = connectionConfiguration["loginAttributes"] - localLoginAttributes = connectionConfiguration["localLoginAttributes"] - - ldapConfiguration = GluuLdapConfiguration() - ldapConfiguration.setConfigId(configId) - ldapConfiguration.setBindDN(bindDN) - ldapConfiguration.setBindPassword(bindPassword) - ldapConfiguration.setServers(Arrays.asList(servers)) - ldapConfiguration.setMaxConnections(maxConnections) - ldapConfiguration.setUseSSL(useSSL) - ldapConfiguration.setBaseDNs(Arrays.asList(baseDNs)) - ldapConfiguration.setPrimaryKey(loginAttributes[0]) - ldapConfiguration.setLocalPrimaryKey(localLoginAttributes[0]) - ldapConfiguration.setUseAnonymousBind(useAnonymousBind) - - ldapExtendedConfigurations.append({ "ldapConfiguration" : ldapConfiguration, "connectionConfiguration" : connectionConfiguration, "loginAttributes" : loginAttributes, "localLoginAttributes" : localLoginAttributes }) - - return ldapExtendedConfigurations - - def containsAttributeString(self, dictionary, attribute): - return ((attribute in dictionary) and StringHelper.isNotEmptyString(dictionary[attribute])) - - def containsAttributeArray(self, dictionary, attribute): - return ((attribute in dictionary) and (len(dictionary[attribute]) > 0)) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/BasicMultiLoginExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/BasicMultiLoginExternalAuthenticator.py deleted file mode 100644 index 1deacebf655..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multi_login/BasicMultiLoginExternalAuthenticator.py +++ /dev/null @@ -1,122 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService -from io.jans.util import StringHelper, ArrayHelper - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (multi login). Initialization" - - login_attributes_list_object = configurationAttributes.get("login_attributes_list") - if (login_attributes_list_object == None): - print "Basic (multi login). Initialization. There is no property login_attributes_list" - return False - - login_attributes_list = login_attributes_list_object.getValue2() - if (StringHelper.isEmpty(login_attributes_list)): - print "Basic (multi login). Initialization. There is no attributes specified in login_attributes property" - return False - - login_attributes_list_array = StringHelper.split(login_attributes_list, ",") - if (ArrayHelper.isEmpty(login_attributes_list_array)): - print "Basic (multi login). Initialization. There is no attributes specified in login_attributes property" - return False - - if (configurationAttributes.containsKey("local_login_attributes_list")): - local_login_attributes_list = configurationAttributes.get("local_login_attributes_list").getValue2() - local_login_attributes_list_array = StringHelper.split(local_login_attributes_list, ",") - else: - print "Basic (multi login). Initialization. There is no property local_login_attributes_list. Assuming that login attributes are equal to local login attributes." - local_login_attributes_list_array = login_attributes_list_array - - if (len(login_attributes_list_array) != len(local_login_attributes_list_array)): - print "Basic (multi login). Initialization. The number of attributes in login_attributes_list and local_login_attributes_list isn't equal" - return False - - self.login_attributes_list_array = login_attributes_list_array - self.local_login_attributes_list_array = local_login_attributes_list_array - - print "Basic (multi login). Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic (multi login). Destroy" - print "Basic (multi login). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Basic (multi login). Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - key_value = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if (StringHelper.isNotEmptyString(key_value) and StringHelper.isNotEmptyString(user_password)): - i = 0 - count = len(self.login_attributes_list_array) - while (i < count): - primary_key = self.login_attributes_list_array[i] - local_primary_key = self.local_login_attributes_list_array[i] - logged_in = authenticationService.authenticate(key_value, user_password, primary_key, local_primary_key) - if (logged_in): - return True - i += 1 - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic (multi login). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/BasicMultipleTestEmailAddressesExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/BasicMultipleTestEmailAddressesExternalAuthenticator.py deleted file mode 100644 index 86561e7cc1a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.multiple_test_email_addresses/BasicMultipleTestEmailAddressesExternalAuthenticator.py +++ /dev/null @@ -1,97 +0,0 @@ - - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.util import StringHelper - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic. Initialization" - print "Basic. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic. Destroy" - print "Basic. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Basic. Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name_array = StringHelper.split(credentials.getUsername(),"+") - - user_name = None - - if len(user_name_array) == 2: - - email_id_array = StringHelper.split(user_name_array[1],"@") - user_name = user_name_array[0] + "@"+ email_id_array[1] - else: - - user_name = user_name_array[0] - - print "Username for authentication is: %s " % user_name - user_password = credentials.getPassword() - - logged_in = False - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - - logged_in = authenticationService.authenticate(user_name, user_password,"mail","mail") - - if (not logged_in): - return False - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Basic. Prepare for Step 1" - return True - else: - return False - - def getNextStep(self, step, context): - return -1 - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/BasicOneSessionExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/BasicOneSessionExternalAuthenticator.py deleted file mode 100644 index b2ca688fb42..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.one_session/BasicOneSessionExternalAuthenticator.py +++ /dev/null @@ -1,118 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.orm import PersistenceEntryManager -from org.gluu.oxauth.model.ldap import TokenEntity -from io.jans.util import StringHelper -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages -from org.gluu.oxauth.model.config import StaticConfiguration - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (one session). Initialization" - self.entryManager = CdiUtil.bean(PersistenceEntryManager) - self.staticConfiguration = CdiUtil.bean(StaticConfiguration) - - print "Basic (one session). Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic (one session). Destroy" - print "Basic (one session). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if step == 1: - print "Basic (one session). Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - logged_in = authenticationService.authenticate(user_name, user_password) - - if not logged_in: - return False - - logged_in = self.isFirstSession(user_name) - if not logged_in: - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Please, end active session first!") - return False - - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "Basic (one session). Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def isFirstSession(self, user_name): - tokenEntity = TokenEntity() - tokenEntity.setDn(self.staticConfiguration.getBaseDn().getClients()) - tokenEntity.setUserId(user_name) - - tokenEntityList = self.entryManager.findEntries(tokenEntity, 1) - print "Basic (one session). isFirstSession. Get result: '%s'" % tokenEntityList - - if (tokenEntityList != None) and (tokenEntityList.size() > 0): - print "Basic (one session). isFirstSession: False" - return False - - print "Basic (one session). isFirstSession: True" - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/PasswordExpiration.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/PasswordExpiration.py deleted file mode 100644 index 9fe12b577e2..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/PasswordExpiration.py +++ /dev/null @@ -1,149 +0,0 @@ -import datetime - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService -from io.jans.util import StringHelper, ArrayHelper -from com.unboundid.util import StaticUtils -from java.util import GregorianCalendar, TimeZone -from java.util import Arrays - - -# This script expect that user has attribute oxPasswordExpirationDate with valid expiration date -class PersonAuthentication(PersonAuthenticationType): - - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (with password update). Initialization" - print "Basic (with password update). Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic (with password update). Destroy" - print "Basic (with password update). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - userService = CdiUtil.bean(UserService) - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - if step == 1: - print "Basic (with password update). Authenticate for step 1" - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - logged_in = authenticationService.authenticate(user_name, user_password) - - if not logged_in: - return False - - find_user_by_uid = authenticationService.getAuthenticatedUser() - user_expDate = find_user_by_uid.getAttribute("oxPasswordExpirationDate", False) - - if user_expDate == None: - print "Basic (with password update). Authenticate for step 1. User has no oxPasswordExpirationDate date" - return False - - dt = StaticUtils.decodeGeneralizedTime(user_expDate) - - # Get Current Date - calendar = GregorianCalendar(TimeZone.getTimeZone("UTC")); - now = calendar.getTime() - if now.compareTo(dt) > 0: - # Add 90 Days to current date - calendar.setTime(now) - calendar.add(calendar.DATE, 1) - dt_plus_90 = calendar.getTime() - expDate = StaticUtils.encodeGeneralizedTime(dt_plus_90) - identity.setWorkingParameter("expDate", expDate) - - return True - elif step == 2: - print "Basic (with password update). Authenticate for step 2" - user = authenticationService.getAuthenticatedUser() - if user == None: - print "Basic (with password update). Authenticate for step 2. Failed to determine user name" - return False - - user_name = user.getUserId() - find_user_by_uid = userService.getUser(user_name) - newExpDate = identity.getWorkingParameter("expDate") - if find_user_by_uid == None: - print "Basic (with password update). Authenticate for step 2. Failed to find user" - return False - print "Basic (with password update). Authenticate for step 2" - update_button = requestParameters.get("loginForm:updateButton") - - if ArrayHelper.isEmpty(update_button): - return True - - find_user_by_uid.setAttribute("oxPasswordExpirationDate", newExpDate) - new_password_array = requestParameters.get("loginForm:password") - if ArrayHelper.isEmpty(new_password_array) or StringHelper.isEmpty(new_password_array[0]): - print "Basic (with password update). Authenticate for step 2. New password is empty" - return False - - new_password = new_password_array[0] - find_user_by_uid.setAttribute("userPassword", new_password) - print "Basic (with password update). Authenticate for step 2. Attempting to set new user '%s' password" % user_name - - userService.updateUser(find_user_by_uid) - print "Basic (with password update). Authenticate for step 2. Password updated successfully" - - return True - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "Basic (with password update). Prepare for Step 1" - return True - elif step == 2: - print "Basic (with password update). Prepare for Step 2" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("expDate") - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - if identity.isSetWorkingParameter("expDate"): - return 2 - else: - return 1 - - def getPageForStep(self, configurationAttributes, step): - if step == 2: - return "/auth/pwd/newpassword.xhtml" - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/README.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/README.md deleted file mode 100644 index bf878afba06..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.password_expiration/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Password Expiration -The script would ask the user to update password after 90 days. diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/BasicResetToStepExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/BasicResetToStepExternalAuthenticator.py deleted file mode 100644 index 8979f0536c7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/basic.reset_to_step/BasicResetToStepExternalAuthenticator.py +++ /dev/null @@ -1,100 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService -from io.jans.util import StringHelper - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Basic (demo reset step). Initialization" - print "Basic (demo reset step). Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Basic (demo reset step). Destroy" - print "Basic (demo reset step). Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if 1 <= step <= 3: - print "Basic (demo reset step). Authenticate for step '%s'" % step - - identity = CdiUtil.bean(Identity) - identity.setWorkingParameter("pass_authentication", False) - - credentials = identity.getCredentials() - user_name = credentials.getUsername() - 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 - - identity.setWorkingParameter("pass_authentication", True) - return True - else: - return False - - def getNextStep(self, configurationAttributes, requestParameters, step): - print "Basic (demo reset step). Get next step for step '%s'" % step - identity = CdiUtil.bean(Identity) - - # If user not pass current step authenticaton redirect to current step - pass_authentication = identity.getWorkingParameter("pass_authentication") - if not pass_authentication: - resultStep = step - print "Basic (demo reset step). Get next step. Changing step to '%s'" % resultStep - return resultStep - - return -1 - - def prepareForStep(self, configurationAttributes, requestParameters, step): - print "Basic (demo reset step). Prepare for step '%s'" % step - if 1 <= step <= 3: - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 3 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/bcrypt_ssha_migration/pwd_migration.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/bcrypt_ssha_migration/pwd_migration.py deleted file mode 100644 index d2f98d896cb..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/bcrypt_ssha_migration/pwd_migration.py +++ /dev/null @@ -1,148 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan, Chris Blanton -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.util import StringHelper -from io.jans.as.server.service import UserService -from io.jans.util.security import BCrypt - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "BCrypt Auth. Initialization" - print "BCrypt Auth. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "BCrypt Auth. Destroy" - print "BCrypt Auth. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "BCrypt Auth. Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - userService = CdiUtil.bean(UserService) - user = userService.getUser(user_name) - hashed_stored_pass = user.getAttribute("userPassword") - - password_schema = '' - - # Determine password schema - # Example for BCrypt: {BCRYPT}$2b$08$71gBXNKJ/iUBXqLjEdEXFesoUYQm5vrpKefi8YhV7ITGfAd9VNFaG - for char in hashed_stored_pass: - if char == '{': - continue - if char == '}': - break - password_schema = password_schema + char - print("Password Schema is: " + password_schema) - - # OpenDJ's SSHA(512) - if 'SSHA' in password_schema: - # Returns True if authenticated on the backend - logged_in = authenticationService.authenticate(user_name, user_password) - - # Pattern match BCRYPT and rewrite to SSHA - elif 'BCRYPT' in password_schema: - # Pull salt from the stored hashed password - salt = hashed_stored_pass[8:] - salt = salt.split("$")[3].strip() - salt = salt[0:22] - salt = '$2a$08$' + salt - - # Create BCrypt hash of challenge cleartext password using the gathered salt - challenge = BCrypt.hashpw(user_password,salt) - - # Strip unnecessary revision($2a$) and rounds(08$) from both hashed passwords for comparison. - challenge = challenge.split("$")[3].strip() - stored = hashed_stored_pass.split("$")[3].strip() - - print("Challenge Salt+Hash: " + challenge) - print("Stored Salt+Hash: " + stored) - - # Compare the hashses and update hash if there is a match. - if challenge in stored: - - # Users hashed challenge password matches the stored hashed password in the backend - # Therefore we update the users password to the backend's password schema by passing it to OpenDJ - print("Updating hash..") - user.setAttribute("userPassword",user_password) - user = userService.updateUser(user) - print("Logging in..") - - # Returns True - logged_in = authenticationService.authenticate(user_name) - - # Catch unknown schema types and output to oxauth_script.log - # This script can be expanded to include other password schemas. - else: - print("Unrecognized algorithm: " + password_schema) - - # If there is no match, logged_in will still be False and authentication will fail. - if (not logged_in): - return False - logged_in = authenticationService.authenticate(user_name) - return logged_in - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "BCrypt Auth. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2/Cas2ExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2/Cas2ExternalAuthenticator.py deleted file mode 100644 index ae18806f7fe..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cas2/Cas2ExternalAuthenticator.py +++ /dev/null @@ -1,338 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -import sys -from java.util import Arrays -from java.util import HashMap -from jakarta.faces.context import FacesContext -from org.apache.http.params import CoreConnectionPNames -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.security import Identity -from io.jans.as.server.service import UserService, AuthenticationService, RequestParameterService -from io.jans.as.server.service.net import HttpService -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper, ArrayHelper -from io.jans.jsf2.service import FacesService - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "CAS2. Initialization" - - if not configurationAttributes.containsKey("cas_host"): - print "CAS2. Initialization. Parameter 'cas_host' is missing" - return False - - self.cas_host = configurationAttributes.get("cas_host").getValue2() - - self.cas_extra_opts = None - if configurationAttributes.containsKey("cas_extra_opts"): - self.cas_extra_opts = configurationAttributes.get("cas_extra_opts").getValue2() - - - self.cas_renew_opt = False - if configurationAttributes.containsKey("cas_renew_opt"): - self.cas_renew_opt = StringHelper.toBoolean(configurationAttributes.get("cas_renew_opt").getValue2(), False) - - self.cas_map_user = False - if configurationAttributes.containsKey("cas_map_user"): - self.cas_map_user = StringHelper.toBoolean(configurationAttributes.get("cas_map_user").getValue2(), False) - - self.cas_enable_server_validation = False - if (configurationAttributes.containsKey("cas_validation_uri") and - configurationAttributes.containsKey("cas_validation_pattern") and - configurationAttributes.containsKey("cas_validation_timeout")): - - print "CAS2. Initialization. Configuring checker client" - self.cas_enable_server_validation = True - - self.cas_validation_uri = configurationAttributes.get("cas_validation_uri").getValue2() - self.cas_validation_pattern = configurationAttributes.get("cas_validation_pattern").getValue2() - cas_validation_timeout = int(configurationAttributes.get("cas_validation_timeout").getValue2()) * 1000 - - httpService = CdiUtil.bean(HttpService) - - self.http_client = httpService.getHttpsClient() - self.http_client_params = self.http_client.getParams() - self.http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, cas_validation_timeout) - - self.cas_alt_auth_mode = None - if configurationAttributes.containsKey("cas_alt_auth_mode"): - self.cas_alt_auth_mode = configurationAttributes.get("cas_alt_auth_mode").getValue2() - - print "CAS2. Initialized successfully" - - return True - - def destroy(self, configurationAttributes): - print "CAS2. Destroy" - if self.cas_enable_server_validation: - print "CAS2. CDestory. Destorying checker client" - self.http_client = None - - print "CAS2. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - if not self.cas_enable_server_validation: - return True - - print "CAS2. isValidAuthenticationMethod" - - httpService = CdiUtil.bean(HttpService) - - try: - http_service_response = httpService.executeGet(self.http_client, self.cas_validation_uri) - except: - print "CAS2. isValidAuthenticationMethod. Exception: ", sys.exc_info()[1] - return False - - try: - http_response = http_service_response.getHttpResponse() - if http_response.getStatusLine().getStatusCode() != 200: - print "CAS2. isValidAuthenticationMethod. Get invalid response from CAS2 server: ", str(http_response.getStatusLine().getStatusCode()) - httpService.consume(http_response) - return False - - validation_response_bytes = httpService.getResponseContent(http_response) - validation_response_string = httpService.convertEntityToString(validation_response_bytes) - httpService.consume(http_response) - finally: - http_service_response.closeConnection() - - if (validation_response_string == None) or (validation_response_string.find(self.cas_validation_pattern) == -1): - print "CAS2. isValidAuthenticationMethod. Get invalid login page from CAS2 server:" - return False - - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return self.cas_alt_auth_mode - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - userService = CdiUtil.bean(UserService) - requestParameterService = CdiUtil.bean(RequestParameterService) - authenticationService = CdiUtil.bean(AuthenticationService) - httpService = CdiUtil.bean(HttpService) - - if step == 1: - print "CAS2. Authenticate for step 1" - ticket_array = requestParameters.get("ticket") - if ArrayHelper.isEmpty(ticket_array): - print "CAS2. Authenticate for step 1. ticket is empty" - return False - - ticket = ticket_array[0] - print "CAS2. Authenticate for step 1. ticket: " + ticket - - if StringHelper.isEmptyString(ticket): - print "CAS2. Authenticate for step 1. ticket is invalid" - return False - - # Validate ticket - facesContext = CdiUtil.bean(FacesContext) - request = facesContext.getExternalContext().getRequest() - - parametersMap = HashMap() - parametersMap.put("service", httpService.constructServerUrl(request) + "/postlogin.htm") - if self.cas_renew_opt: - parametersMap.put("renew", "true") - parametersMap.put("ticket", ticket) - cas_service_request_uri = requestParameterService.parametersAsString(parametersMap) - cas_service_request_uri = self.cas_host + "/serviceValidate?" + cas_service_request_uri - if self.cas_extra_opts != None: - cas_service_request_uri = cas_service_request_uri + "&" + self.cas_extra_opts - - print "CAS2. Authenticate for step 1. cas_service_request_uri: " + cas_service_request_uri - - http_client = httpService.getHttpsClient() - http_service_response = httpService.executeGet(http_client, cas_service_request_uri) - try: - validation_content = httpService.convertEntityToString(httpService.getResponseContent(http_service_response.getHttpResponse())) - finally: - http_service_response.closeConnection() - - print "CAS2. Authenticate for step 1. validation_content: " + validation_content - if StringHelper.isEmpty(validation_content): - print "CAS2. Authenticate for step 1. Ticket validation response is invalid" - return False - - cas2_auth_failure = self.parse_tag(validation_content, "cas:authenticationFailure") - print "CAS2. Authenticate for step 1. cas2_auth_failure: ", cas2_auth_failure - - cas2_user_uid = self.parse_tag(validation_content, "cas:user") - print "CAS2. Authenticate for step 1. cas2_user_uid: ", cas2_user_uid - - if (cas2_auth_failure != None) or (cas2_user_uid == None): - print "CAS2. Authenticate for step 1. Ticket is invalid" - return False - - if self.cas_map_user: - print "CAS2. Authenticate for step 1. Attempting to find user by oxExternalUid: cas2:" + cas2_user_uid - - # Check if the is user with specified cas2_user_uid - find_user_by_uid = userService.getUserByAttribute("oxExternalUid", "cas2:" + cas2_user_uid) - - if find_user_by_uid == None: - print "CAS2. Authenticate for step 1. Failed to find user" - print "CAS2. Authenticate for step 1. Setting count steps to 2" - identity.setWorkingParameter("cas2_count_login_steps", 2) - identity.setWorkingParameter("cas2_user_uid", cas2_user_uid) - return True - - found_user_name = find_user_by_uid.getUserId() - print "CAS2. Authenticate for step 1. found_user_name: " + found_user_name - - authenticationService.authenticate(found_user_name) - - print "CAS2. Authenticate for step 1. Setting count steps to 1" - identity.setWorkingParameter("cas2_count_login_steps", 1) - - return True - else: - print "CAS2. Authenticate for step 1. Attempting to find user by uid:" + cas2_user_uid - - # Check if there is user with specified cas2_user_uid - find_user_by_uid = userService.getUser(cas2_user_uid) - if find_user_by_uid == None: - print "CAS2. Authenticate for step 1. Failed to find user" - return False - - found_user_name = find_user_by_uid.getUserId() - print "CAS2. Authenticate for step 1. found_user_name: " + found_user_name - - authenticationService.authenticate(found_user_name) - - print "CAS2. Authenticate for step 1. Setting count steps to 1" - identity.setWorkingParameter("cas2_count_login_steps", 1) - - return True - elif step == 2: - print "CAS2. Authenticate for step 2" - - if identity.isSetWorkingParameter("cas2_user_uid"): - print "CAS2. Authenticate for step 2. cas2_user_uid is empty" - return False - - cas2_user_uid = identity.getWorkingParameter("cas2_user_uid") - passed_step1 = StringHelper.isNotEmptyString(cas2_user_uid) - if not passed_step1: - return False - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - logged_in = authenticationService.authenticate(user_name, user_password) - - if not logged_in: - return False - - # Check if there is user which has cas2_user_uid - # Avoid mapping CAS2 account to more than one IDP account - find_user_by_uid = userService.getUserByAttribute("oxExternalUid", "cas2:" + cas2_user_uid) - - if find_user_by_uid == None: - # Add cas2_user_uid to user one id UIDs - find_user_by_uid = userService.addUserAttribute(user_name, "oxExternalUid", "cas2:" + cas2_user_uid) - if find_user_by_uid == None: - print "CAS2. Authenticate for step 2. Failed to update current user" - return False - - return True - else: - found_user_name = find_user_by_uid.getUserId() - print "CAS2. Authenticate for step 2. found_user_name: " + found_user_name - - if StringHelper.equals(user_name, found_user_name): - return True - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "CAS2. Prepare for step 1" - - requestParameterService = CdiUtil.bean(RequestParameterService) - httpService = CdiUtil.bean(HttpService) - - facesContext = CdiUtil.bean(FacesContext) - request = facesContext.getExternalContext().getRequest() - - parametersMap = HashMap() - parametersMap.put("service", httpService.constructServerUrl(request) + "/postlogin.htm") - if self.cas_renew_opt: - parametersMap.put("renew", "true") - cas_service_request_uri = requestParameterService.parametersAsString(parametersMap) - cas_service_request_uri = self.cas_host + "/login?" + cas_service_request_uri - if self.cas_extra_opts != None: - cas_service_request_uri = cas_service_request_uri + "&" + self.cas_extra_opts - - print "CAS2. Prepare for step 1. cas_service_request_uri: " + cas_service_request_uri - facesService = CdiUtil.bean(FacesService) - facesService.redirectToExternalURL(cas_service_request_uri) - - return True - elif step == 2: - print "CAS2. Prepare for step 2" - - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 2: - return Arrays.asList("cas2_count_login_steps", "cas2_user_uid") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - if identity.isSetWorkingParameter("cas2_count_login_steps"): - return int(identity.getWorkingParameter("cas2_count_login_steps")) - - return 2 - - def getPageForStep(self, configurationAttributes, step): - identity = CdiUtil.bean(Identity) - if step == 1: - return "/auth/cas2/cas2login.xhtml" - return "/auth/cas2/cas2postlogin.xhtml" - - def parse_tag(self, str, tag): - tag1_pos1 = str.find("<" + tag) - # No tag found, return empty string. - if tag1_pos1 == -1: return None - tag1_pos2 = str.find(">", tag1_pos1) - if tag1_pos2 == -1: return None - tag2_pos1 = str.find("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 MxnWAAKKuVS0np_cb^rhX diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.dia b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.dia deleted file mode 100644 index 3952dea0b3cf9456964a5495c8161efc9d2b9265..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11048 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 diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.jpg b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/docs/Cert design.jpg deleted file mode 100644 index 555079788a9b0bc44b6aa3c8c9806e8c5bfb01a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110176 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 UcxeXB_eKU_mn%(-ax(P)0BudkbpQYW diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/cert_creds.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/cert_creds.json deleted file mode 100644 index 2e7df116100..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/cert_creds.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recaptcha":{ - "enabled":false, - "site_key":"", - "secret_key":"" - } -} diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/generated_certs.zip b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/cert/sample/generated_certs.zip deleted file mode 100644 index cbd235c2039654754ba7511757872f3c66563901..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53946 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 diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/ciba/FirebaseEndUserNotification.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/ciba/FirebaseEndUserNotification.py deleted file mode 100644 index 3d7837a369a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/ciba/FirebaseEndUserNotification.py +++ /dev/null @@ -1,68 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Milton BO -# -# - -from org.gluu.oxauth.client.fcm import FirebaseCloudMessagingResponse -from org.gluu.oxauth.client.fcm import FirebaseCloudMessagingClient -from org.gluu.oxauth.client.fcm import FirebaseCloudMessagingRequest -from io.jans.as.server.util import RedirectUri -from io.jans.model.custom.script.type.ciba import EndUserNotificationType -from java.lang import String -from java.util import UUID - -class EndUserNotification(EndUserNotificationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, configurationAttributes): - print "Firebase EndUserNotification script. Initializing ..." - print "Firebase EndUserNotification script. Initialized successfully" - - return True - - def destroy(self, configurationAttributes): - print "Firebase EndUserNotification script. Destroying ..." - print "Firebase EndUserNotification script. Destroyed successfully" - return True - - def getApiVersion(self): - return 1 - - # Returns boolean true or false depending on the process, if the notification - # is sent successfully or not. - def notifyEndUser(self, context): - print 'Sending push notification using Firebase Cloud Messaging' - appConfiguration = context.getAppConfiguration() - encryptionService = context.getEncryptionService() - clientId = appConfiguration.getBackchannelClientId() - redirectUri = appConfiguration.getBackchannelRedirectUri() - url = appConfiguration.getCibaEndUserNotificationConfig().getNotificationUrl() - key = encryptionService.decrypt(appConfiguration.getCibaEndUserNotificationConfig().getNotificationKey(), True) - to = context.getDeviceRegistrationToken() - title = "oxAuth Authentication Request" - body = "Client Initiated Backchannel Authentication (CIBA)" - - authorizationRequestUri = RedirectUri(appConfiguration.getAuthorizationEndpoint()) - authorizationRequestUri.addResponseParameter("client_id", clientId) - authorizationRequestUri.addResponseParameter("response_type", "id_token") - authorizationRequestUri.addResponseParameter("scope", context.getScope()) - authorizationRequestUri.addResponseParameter("acr_values", context.getAcrValues()) - authorizationRequestUri.addResponseParameter("redirect_uri", redirectUri) - authorizationRequestUri.addResponseParameter("state", UUID.randomUUID().toString()) - authorizationRequestUri.addResponseParameter("nonce", UUID.randomUUID().toString()) - authorizationRequestUri.addResponseParameter("prompt", "consent") - authorizationRequestUri.addResponseParameter("auth_req_id", context.getAuthReqId()) - - clickAction = authorizationRequestUri.toString() - - firebaseCloudMessagingRequest = FirebaseCloudMessagingRequest(key, to, title, body, clickAction) - firebaseCloudMessagingClient = FirebaseCloudMessagingClient(url) - firebaseCloudMessagingClient.setRequest(firebaseCloudMessagingRequest) - firebaseCloudMessagingResponse = firebaseCloudMessagingClient.exec() - - responseStatus = firebaseCloudMessagingResponse.getStatus() - print "CIBA: firebase cloud messaging result status " + str(responseStatus) - return (responseStatus >= 200 and responseStatus < 300 ) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/compromised_password.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/compromised_password.py deleted file mode 100644 index b35cd40a58a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/compromised_password/compromised_password.py +++ /dev/null @@ -1,223 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService -from io.jans.util import StringHelper -import javax.crypto.spec.SecretKeySpec as SecretKeySpec -import javax.crypto.spec.IvParameterSpec as IvParameterSpec -import javax.crypto.Cipher -from javax.crypto import * -from io.jans.util import ArrayHelper -from java.util import Arrays -import urllib, urllib2, json - -import java -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "compromised_password. Initialization" - if not configurationAttributes.containsKey("secret_question"): - print "compromised_password. Initialization. Property secret_question is mandatory" - return False - self.secretquestion = configurationAttributes.get("secret_question").getValue2() - - if not configurationAttributes.containsKey("credentials_file"): - print "credentials_file property not defined" - return False - self.credentialfile = configurationAttributes.get("credentials_file").getValue2() - - if not configurationAttributes.containsKey("secret_answer"): - print "compromised_password. Initialization. Property secret_answer is mandatory" - return False - self.secretanswer = configurationAttributes.get("secret_answer").getValue2() - print "compromised_password. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "compromised_password. Destroy" - print "compromised_password. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - - if step == 1: - credentials = identity.getCredentials() - user_name = credentials.getUsername() - 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 - else: - find_user_by_uid = authenticationService.getAuthenticatedUser() - status_attribute_value = userService.getCustomAttribute(find_user_by_uid, "mail") - user_mail = status_attribute_value.getValue() - self.setRequestScopedParameters(identity) - isCompromised = False - isCompromised = self.is_compromised(user_mail,user_password,configurationAttributes) - if(isCompromised): - identity.setWorkingParameter("pwd_compromised", isCompromised) - identity.setWorkingParameter("user_name", user_name) - return True - else: - return True - elif step == 2: - print "compromised_password. Authenticate for step 2" - form_answer_array = requestParameters.get("loginForm:question") - if ArrayHelper.isEmpty(form_answer_array): - return False - form_answer = form_answer_array[0] - if (form_answer == self.secretanswer): - return True - return False - elif step == 3: - authenticationService = CdiUtil.bean(AuthenticationService) - print "compromised_password (with password update). Authenticate for step 3" - userService = CdiUtil.bean(UserService) - update_button = requestParameters.get("loginForm:updateButton") - new_password_array = requestParameters.get("new_password") - if ArrayHelper.isEmpty(new_password_array) or StringHelper.isEmpty(new_password_array[0]): - print "compromised_password (with password update). Authenticate for step 3. New password is empty" - return False - new_password = new_password_array[0] - - user = authenticationService.getAuthenticatedUser() - if user == None: - print "compromised_password (with password update). Authenticate for step 3. Failed to determine user name" - return False - - user_name = user.getUserId() - print "compromised_password (with password update). Authenticate for step 3. Attempting to set new user '" + user_name + "' password" - find_user_by_uid = userService.getUser(user_name) - if (find_user_by_uid == None): - print "compromised_password (with password update). Authenticate for step 3. Failed to find user" - return False - - find_user_by_uid.setAttribute("userPassword", new_password) - userService.updateUser(find_user_by_uid) - print "compromised_password (with password update). Authenticate for step 3. Password updated successfully" - logged_in = authenticationService.authenticate(user_name) - return True - - def prepareForStep(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - self.setRequestScopedParameters(identity) - session_attributes = identity.getSessionId().getSessionAttributes() - pwdcompromised = session_attributes.get("pwd_compromised") - if(pwdcompromised != None): - if step == 1: - print "compromised_password. Prepare for step 1" - return True - elif step == 2: - print "compromised_password. Prepare for step 2" - return True - return False - else: - print "compromised_password. Prepare for step 1" - return True - - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("pwd_compromised","user_name") - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - self.setRequestScopedParameters(identity) - self.setRequestScopedParameters(identity) - session_attributes = identity.getSessionId().getSessionAttributes() - pwdcompromised = session_attributes.get("pwd_compromised") - if(pwdcompromised != None): - return 3 - return 1 - - def getPageForStep(self, configurationAttributes, step): - identity = CdiUtil.bean(Identity) - session_attributes = identity.getSessionId().getSessionAttributes() - pwdcompromised = session_attributes.get("pwd_compromised") - if(pwdcompromised != None): - if step == 2: - return "/auth/compromised/complogin.xhtml" - elif step == 3: - return "/auth/compromised/newpassword.xhtml" - return "" - else: - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def setRequestScopedParameters(self, identity): - identity.setWorkingParameter("question_label", self.secretquestion) - - def is_compromised(self, userid, password,configurationAttributes): - print "Vericloud APIs Initialization" - - vericloud_gluu_creds_file = self.credentialfile - # Load credentials from file - f = open(vericloud_gluu_creds_file, 'r') - try: - creds = json.loads(f.read()) - except: - print "Vericloud API. Initialize notification services. Failed to load credentials from file:", vericloud_gluu_creds_file - return False - finally: - f.close() - - try: - url = str(creds["api_url"]) - api_key=str(creds["api_key"]) - api_secret= str(creds["api_secret"]) - except: - print "Vericloud API. Initialize notification services. Invalid credentials file '%s' format:" % super_gluu_creds_file - return False - - - reqdata = {"mode":"search_leaked_password_with_userid", "api_key": api_key, "api_secret": api_secret, "userid": userid} - reqdata = urllib.urlencode(reqdata) - resp = urllib2.urlopen(urllib2.Request(url, reqdata)).read() - resp = json.loads(resp) - if resp['result'] != 'succeeded': - return None - for pass_enc in resp['passwords_encrypted']: - plaintext = self.AESCipherdecrypt(api_secret, pass_enc) - if (len(password), password[0], password[-1]) == (len(plaintext), plaintext[0], plaintext[-1]) : - return True - return False - - def AESCipherdecrypt(self, key, enc ): - enc, iv = enc.split(':') - cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING") - cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key.decode("hex"), "AES"),IvParameterSpec(iv.decode("hex"))) - decrypted_password = cipher.doFinal(enc.decode("hex")) - return decrypted_password.tostring() diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/Attributes.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/Attributes.json deleted file mode 100644 index 951db1ef88e..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/Attributes.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "en": { - "givenName": "First Name", - "sn": "Last Name", - "mail": "Email", - "familyName": "Middle Name" - }, -"passStrength":2, -"domains": [] -} diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/README.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/README.md deleted file mode 100644 index c873b353973..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/README.md +++ /dev/null @@ -1,11 +0,0 @@ -In order to exceute the custom registration workflow, - -1. Add the following custom property(key:value) in the script properties: - -attributes_json_file_path: /etc/Attributes.json - -and place Attributes.json file in the path specified in the custom property. - -2. Place the reg.xhtml file in /opt/gluu/jetty/oxauth/custom/pages/auth/ directory. - -3. Enable the script and set it as the default authentication method. diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/reg.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/reg.xhtml deleted file mode 100644 index 24f3ea2da55..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/reg.xhtml +++ /dev/null @@ -1,264 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/register.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/register.py deleted file mode 100644 index 275b37217ed..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/custom_registration/register.py +++ /dev/null @@ -1,268 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Jose Gonzalez -# Author: Gasmyr Mougang - -from org.gluu.oxauth.model.common import User, WebKeyStorage -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, AuthenticationService -from io.jans.as.server.util import ServerUtil -from io.jans.util import StringHelper, ArrayHelper -from java.util import Arrays -from jakarta.faces.application import FacesMessage -from io.jans.jsf2.message import FacesMessages -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from io.jans.service import MailService - - -import org.codehaus.jettison.json.JSONArray as JSONArray - -import json, ast -import java -import random -import jarray -import smtplib - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - self.emailid = None - self.identity = CdiUtil.bean(Identity) - - def init(self, customScript, configurationAttributes): - - print "Register. Initialized successfully" - if not (configurationAttributes.containsKey("attributes_json_file_path")): - #print "Cert. Initialization. Property chain_cert_file_path is mandatory" - return False - self.attributes_json_file_path = configurationAttributes.get("attributes_json_file_path").getValue2() - - return True - - def destroy(self, configurationAttributes): - print "Register. Destroy" - print "Register. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - - userService = CdiUtil.bean(UserService) - identity = CdiUtil.bean(Identity) - authenticationService = CdiUtil.bean(AuthenticationService) - - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - - session_attributes = self.identity.getSessionId().getSessionAttributes() - form_passcode = ServerUtil.getFirstValue(requestParameters, "passcode") - - - print "Register. form_response_passcode: %s" % str(form_passcode) - - if step == 1: - print "inside step 1" - ufnm = ServerUtil.getFirstValue(requestParameters, "fnm") - ulnm = ServerUtil.getFirstValue(requestParameters, "lnm") - umnm = ServerUtil.getFirstValue(requestParameters, "mnm") - umail = ServerUtil.getFirstValue(requestParameters, "email") - upass = ServerUtil.getFirstValue(requestParameters, "pass") - - - - #rufnm1 = identity.getWorkingParameter("vufnm") - #print "rufnm" - #print rufnm1 - - #print "Register. Step 1 Password Authentication" - - - - # Generate Random six digit code and store it in array - code = random.randint(100000, 999999) - - - # Get code and save it in LDAP temporarily with special session entry - self.identity.setWorkingParameter("vufnm", ufnm) - self.identity.setWorkingParameter("vulnm", ulnm) - self.identity.setWorkingParameter("vumnm", umnm) - self.identity.setWorkingParameter("vumail", umail) - self.identity.setWorkingParameter("vupass", upass) - self.identity.setWorkingParameter("code", code) - - try: - mailService = CdiUtil.bean(MailService) - subject = "Registration Details" - - - body = "

Welcome


" - - if ufnm is not None: - body = body + "

First Name : "+str(ufnm)+",

" - - else: - body = body - - - if ulnm is not None: - body = body + "

Last Name "+str(ulnm)+",

" - - else: - body = body - - - if umnm is not None: - body = body + "

Middle Name "+str(umnm)+",

" - - else: - body = body - - body = body + "

Email : "+str(umail)+",

Password : "+str(upass)+",

Use %s OTP to finish Registration.

" - - - mailService.sendMail(umail, None, subject, body, body) - - - return True - except Exception, ex: - facesMessages.add(FacesMessage.SEVERITY_ERROR,"Failed to send message to mobile phone") - print "Register. Error sending message to Twilio" - print "Register. Unexpected error:", ex - - return False - elif step == 2: - # Retrieve the session attribute - print "Register. Step 2 SMS/OTP Authentication" - code = session_attributes.get("code") - rufnm = identity.getWorkingParameter("vufnm") - rulnm = identity.getWorkingParameter("vulnm") - rumnm = identity.getWorkingParameter("vumnm") - rumail = identity.getWorkingParameter("vumail") - rupass = identity.getWorkingParameter("vupass") - - - - - - print "----------------------------------" - print "Register. Code: %s" % str(code) - print "----------------------------------" - - if code is None: - print "Register. Failed to find previously sent code" - return False - - if form_passcode is None: - print "Register. Passcode is empty" - return False - - if len(form_passcode) != 6: - print "Register. Passcode from response is not 6 digits: %s" % form_passcode - return False - - if form_passcode == code: - print "Register, SUCCESS! User entered the same code!" - - newUser = User() - newUser.setAttribute("givenName", rufnm) - newUser.setAttribute("sn", rulnm) - newUser.setAttribute("middleName", rumnm) - newUser.setAttribute("mail", rumail) - newUser.setAttribute("uid", rufnm) - newUser.setAttribute("userPassword", rupass) - userService.addUser(newUser, True) - - logged_in = False - logged_in = authenticationService.authenticate(rufnm, rupass) - - if (not logged_in): - return False - - return True - - #return True - - print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - print "Register. FAIL! User entered the wrong code! %s != %s" % (form_passcode, code) - print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" - #facesMessages.add(facesMessage.SEVERITY_ERROR, "Incorrect Twilio code, please try again.") - - - - - - - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if step == 1: - print "Register. Prepare for Step 1" - identity = CdiUtil.bean(Identity) - print self.getAttributesFromJson() - print "pass strength" - print self.getPasswordStrength() - identity.setWorkingParameter("CustomAtrributes", self.getAttributesFromJson()) - identity.setWorkingParameter("passStrength", str(self.getPasswordStrength())) - return True - elif step == 2: - print "Register. Prepare for Step 2" - return True - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 1: - return Arrays.asList("CustomAtrributes","PasswordStrength") - elif step == 2: - return Arrays.asList("code","vufnm","vulnm","vumnm","vumail","vupass") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 2 - - def getPageForStep(self, configurationAttributes, step): - if step == 1: - return "/auth/reg.xhtml" - elif step == 2: - return "/auth/otp_sms/otp_sms.xhtml" - - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def getAttributesFromJson(self): - f = open(self.attributes_json_file_path) - data = json.load(f) - data = ast.literal_eval(json.dumps(data)) - attributes = data["en"].keys() - - jsonString = ",".join(attributes) - return jsonString - def getPasswordStrength(self): - f = open(self.attributes_json_file_path) - data = json.load(f) - data = ast.literal_eval(json.dumps(data)) - strength = data["passStrength"] - return strength diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/FortinetExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/FortinetExternalAuthenticator.py deleted file mode 100644 index 1660eca5aa9..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/fortinet/FortinetExternalAuthenticator.py +++ /dev/null @@ -1,127 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Madhumita Subramaniam -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from io.jans.util import StringHelper - -from net.sourceforge.jradiusclient import RadiusClient -from net.sourceforge.jradiusclient import RadiusAttribute -from net.sourceforge.jradiusclient import RadiusAttributeValues -from net.sourceforge.jradiusclient import RadiusPacket - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Radius. Initialization" - if not configurationAttributes.containsKey("RADIUS_SERVER_IP"): - print "Fortinet. Initialization. Property RADIUS_SERVER_IP is mandatory" - return False - self.RADIUS_SERVER_IP = configurationAttributes.get("RADIUS_SERVER_IP").getValue2() - - if not configurationAttributes.containsKey("RADIUS_SERVER_SECRET"): - print "Fortinet. Initialization. Property RADIUS_SERVER_SECRET is mandatory" - return False - self.RADIUS_SERVER_SECRET = configurationAttributes.get("RADIUS_SERVER_SECRET").getValue2() - - if not configurationAttributes.containsKey("RADIUS_SERVER_AUTH_PORT"): - print "Fortinet. Initialization. Property RADIUS_SERVER_AUTH_PORT is mandatory" - return False - self.RADIUS_SERVER_AUTH_PORT = configurationAttributes.get("RADIUS_SERVER_AUTH_PORT").getValue2() - - if not configurationAttributes.containsKey("RADIUS_SERVER_ACCT_PORT"): - print "Fortinet. Initialization. Property RADIUS_SERVER_ACCT_PORT is mandatory" - return False - self.RADIUS_SERVER_ACCT_PORT = configurationAttributes.get("RADIUS_SERVER_ACCT_PORT").getValue2() - - print "Radius. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Radius. Destroy" - print "Radius. Destroyed successfully" - return True - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def getApiVersion(self): - return 11 - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Radius. Authenticate for step 1" - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - if StringHelper.isNotEmptyString(user_name ) and StringHelper.isNotEmptyString(user_password ): - user_exists_in_gluu = authenticationService.authenticate(user_name ) - if user_exists_in_gluu : - client = RadiusClient(self.RADIUS_SERVER_IP,int (self.RADIUS_SERVER_AUTH_PORT), int(self.RADIUS_SERVER_ACCT_PORT), self.RADIUS_SERVER_SECRET) - accessRequest = RadiusPacket(RadiusPacket.ACCESS_REQUEST) - userNameAttribute = RadiusAttribute(RadiusAttributeValues.USER_NAME,user_name ) - userPasswordAttribute = RadiusAttribute(RadiusAttributeValues.USER_PASSWORD,user_password ) - accessRequest.setAttribute(userNameAttribute) - accessRequest.setAttribute(userPasswordAttribute) - accessResponse = client.authenticate(accessRequest) - print "Packet type - %s " % accessResponse.getPacketType() - if accessResponse.getPacketType() == RadiusPacket.ACCESS_ACCEPT: - return True - #elif accessResponse.getPacketType() == RadiusPacket.ACCESS_CHALLENGE: - # return False - - - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Radius. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - - def printRadiusPacket(self, radiusPacket): - attributes = radiusPacket.getAttributes() - for attribute in attributes: - print("%s : %s" %attribute.getType() % attribute.getValue) \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/GooglePlusExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/GooglePlusExternalAuthenticator.py deleted file mode 100644 index 194cd39a498..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/GooglePlusExternalAuthenticator.py +++ /dev/null @@ -1,557 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -import java -import json -from java.util import Arrays, HashMap, IdentityHashMap -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from org.gluu.oxauth.client import TokenClient, TokenRequest, UserInfoClient -from org.gluu.oxauth.model.common import GrantType, AuthenticationMethod -from org.gluu.oxauth.model.common import User -from org.gluu.oxauth.model.jwt import Jwt, JwtClaimName -from io.jans.as.server.security import Identity -from io.jans.as.server.service import UserService, ClientService, AuthenticationService -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper, ArrayHelper - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Google+ Initialization" - - if (not configurationAttributes.containsKey("gplus_client_secrets_file")): - print "Google+ Initialization. The property gplus_client_secrets_file is empty" - return False - - clientSecretsFile = configurationAttributes.get("gplus_client_secrets_file").getValue2() - self.clientSecrets = self.loadClientSecrets(clientSecretsFile) - if (self.clientSecrets == None): - print "Google+ Initialization. File with Google+ client secrets should be not empty" - return False - - self.attributesMapping = None - if (configurationAttributes.containsKey("gplus_remote_attributes_list") and - configurationAttributes.containsKey("gplus_local_attributes_list")): - - remoteAttributesList = configurationAttributes.get("gplus_remote_attributes_list").getValue2() - if (StringHelper.isEmpty(remoteAttributesList)): - print "Google+ Initialization. The property gplus_remote_attributes_list is empty" - return False - - localAttributesList = configurationAttributes.get("gplus_local_attributes_list").getValue2() - if (StringHelper.isEmpty(localAttributesList)): - print "Google+ Initialization. The property gplus_local_attributes_list is empty" - return False - - self.attributesMapping = self.prepareAttributesMapping(remoteAttributesList, localAttributesList) - if (self.attributesMapping == None): - print "Google+ Initialization. The attributes mapping isn't valid" - return False - - self.extensionModule = None - if (configurationAttributes.containsKey("extension_module")): - extensionModuleName = configurationAttributes.get("extension_module").getValue2() - try: - self.extensionModule = __import__(extensionModuleName) - extensionModuleInitResult = self.extensionModule.init(configurationAttributes) - if (not extensionModuleInitResult): - return False - except ImportError, ex: - print "Google+ Initialization. Failed to load gplus_extension_module: '%s'" % extensionModuleName - print "Google+ Initialization. Unexpected error:", ex - return False - - print "Google+ Initialized successfully" - return True - - def destroy(self, authConfiguration): - print "Google+ Destroy" - print "Google+ Destroyed successfully" - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - - mapUserDeployment = False - enrollUserDeployment = False - if (configurationAttributes.containsKey("gplus_deployment_type")): - deploymentType = StringHelper.toLowerCase(configurationAttributes.get("gplus_deployment_type").getValue2()) - - if (StringHelper.equalsIgnoreCase(deploymentType, "map")): - mapUserDeployment = True - if (StringHelper.equalsIgnoreCase(deploymentType, "enroll")): - enrollUserDeployment = True - - if (step == 1): - print "Google+ Authenticate for step 1" - - gplusAuthCodeArray = requestParameters.get("gplus_auth_code") - gplusAuthCode = gplusAuthCodeArray[0] - - # Check if user uses basic method to log in - useBasicAuth = False - if (StringHelper.isEmptyString(gplusAuthCode)): - useBasicAuth = True - - # Use basic method to log in - if (useBasicAuth): - print "Google+ Authenticate for step 1. Basic authentication" - - identity.setWorkingParameter("gplus_count_login_steps", 1) - - credentials = identity.getCredentials() - - userName = credentials.getUsername() - userPassword = credentials.getPassword() - - loggedIn = False - if (StringHelper.isNotEmptyString(userName) and StringHelper.isNotEmptyString(userPassword)): - userService = CdiUtil.bean(UserService) - loggedIn = authenticationService.authenticate(userName, userPassword) - - if (not loggedIn): - return False - - return True - - # Use Google+ method to log in - print "Google+ Authenticate for step 1. gplusAuthCode:", gplusAuthCode - - currentClientSecrets = self.getCurrentClientSecrets(self.clientSecrets, configurationAttributes, requestParameters) - if (currentClientSecrets == None): - print "Google+ Authenticate for step 1. Client secrets configuration is invalid" - return False - - print "Google+ Authenticate for step 1. Attempting to gets tokens" - tokenResponse = self.getTokensByCode(self.clientSecrets, configurationAttributes, gplusAuthCode) - if ((tokenResponse == None) or (tokenResponse.getIdToken() == None) or (tokenResponse.getAccessToken() == None)): - print "Google+ Authenticate for step 1. Failed to get tokens" - return False - else: - print "Google+ Authenticate for step 1. Successfully gets tokens" - - jwt = Jwt.parse(tokenResponse.getIdToken()) - # TODO: Validate ID Token Signature - - gplusUserUid = jwt.getClaims().getClaimAsString(JwtClaimName.SUBJECT_IDENTIFIER) - print "Google+ Authenticate for step 1. Found Google user ID in the ID token: '%s'" % gplusUserUid - - if (mapUserDeployment): - # Use mapping to local IDP user - print "Google+ Authenticate for step 1. Attempting to find user by oxExternalUid: 'gplus:%s'" % gplusUserUid - - # Check if there is user with specified gplusUserUid - foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) - - if (foundUser == None): - print "Google+ Authenticate for step 1. Failed to find user" - print "Google+ Authenticate for step 1. Setting count steps to 2" - identity.setWorkingParameter("gplus_count_login_steps", 2) - identity.setWorkingParameter("gplus_user_uid", gplusUserUid) - return True - - foundUserName = foundUser.getUserId() - print "Google+ Authenticate for step 1. foundUserName: '%s'" % foundUserName - - userAuthenticated = authenticationService.authenticate(foundUserName) - if (userAuthenticated == False): - print "Google+ Authenticate for step 1. Failed to authenticate user" - return False - - print "Google+ Authenticate for step 1. Setting count steps to 1" - identity.setWorkingParameter("gplus_count_login_steps", 1) - - postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) - print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult - - return postLoginResult - elif (enrollUserDeployment): - # Use auto enrollment to local IDP - print "Google+ Authenticate for step 1. Attempting to find user by oxExternalUid: 'gplus:%s'" % gplusUserUid - - # Check if there is user with specified gplusUserUid - foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) - - if (foundUser == None): - # Auto user enrollemnt - print "Google+ Authenticate for step 1. There is no user in LDAP. Adding user to local LDAP" - - print "Google+ Authenticate for step 1. Attempting to gets user info" - userInfoResponse = self.getUserInfo(currentClientSecrets, configurationAttributes, tokenResponse.getAccessToken()) - if ((userInfoResponse == None) or (userInfoResponse.getClaims().size() == 0)): - print "Google+ Authenticate for step 1. Failed to get user info" - return False - else: - print "Google+ Authenticate for step 1. Successfully gets user info" - - gplusResponseAttributes = userInfoResponse.getClaims() - - # Convert Google+ user claims to lover case - gplusResponseNormalizedAttributes = HashMap() - for gplusResponseAttributeEntry in gplusResponseAttributes.entrySet(): - gplusResponseNormalizedAttributes.put( - StringHelper.toLowerCase(gplusResponseAttributeEntry.getKey()), gplusResponseAttributeEntry.getValue()) - - currentAttributesMapping = self.getCurrentAttributesMapping(self.attributesMapping, configurationAttributes, requestParameters) - print "Google+ Authenticate for step 1. Using next attributes mapping '%s'" % currentAttributesMapping - - newUser = User() - for attributesMappingEntry in currentAttributesMapping.entrySet(): - remoteAttribute = attributesMappingEntry.getKey() - localAttribute = attributesMappingEntry.getValue() - - localAttributeValue = gplusResponseNormalizedAttributes.get(remoteAttribute) - if (localAttribute != None): - newUser.setAttribute(localAttribute, localAttributeValue) - - if (newUser.getAttribute("sn") == None): - newUser.setAttribute("sn", gplusUserUid) - - if (newUser.getAttribute("cn") == None): - newUser.setAttribute("cn", gplusUserUid) - - # Add mail to oxTrustEmail so that the user's - # email is available through the SCIM interface - # too. - if (newUser.getAttribute("oxTrustEmail") is None and - newUser.getAttribute("mail") is not None): - oxTrustEmail = { - "value": newUser.getAttribute("mail"), - "display": newUser.getAttribute("mail"), - "primary": True, - "operation": None, - "reference": None, - "type": "other" - } - newUser.setAttribute("oxTrustEmail", json.dumps(oxTrustEmail)) - - newUser.setAttribute("oxExternalUid", "gplus:" + gplusUserUid) - print "Google+ Authenticate for step 1. Attempting to add user '%s' with next attributes '%s'" % (gplusUserUid, newUser.getCustomAttributes()) - - foundUser = userService.addUser(newUser, True) - print "Google+ Authenticate for step 1. Added new user with UID: '%s'" % foundUser.getUserId() - - foundUserName = foundUser.getUserId() - print "Google+ Authenticate for step 1. foundUserName: '%s'" % foundUserName - - userAuthenticated = authenticationService.authenticate(foundUserName) - if (userAuthenticated == False): - print "Google+ Authenticate for step 1. Failed to authenticate user" - return False - - print "Google+ Authenticate for step 1. Setting count steps to 1" - identity.setWorkingParameter("gplus_count_login_steps", 1) - - print "Google+ Authenticate for step 1. Attempting to run extension postLogin" - postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) - print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult - - return postLoginResult - else: - # Check if there is user with specified gplusUserUid - print "Google+ Authenticate for step 1. Attempting to find user by uid: '%s'" % gplusUserUid - - foundUser = userService.getUser(gplusUserUid) - if (foundUser == None): - print "Google+ Authenticate for step 1. Failed to find user" - return False - - foundUserName = foundUser.getUserId() - print "Google+ Authenticate for step 1. foundUserName: '%s'" % foundUserName - - userAuthenticated = authenticationService.authenticate(foundUserName) - if (userAuthenticated == False): - print "Google+ Authenticate for step 1. Failed to authenticate user" - return False - - print "Google+ Authenticate for step 1. Setting count steps to 1" - identity.setWorkingParameter("gplus_count_login_steps", 1) - - postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) - print "Google+ Authenticate for step 1. postLoginResult: '%s'" % postLoginResult - - return postLoginResult - elif (step == 2): - print "Google+ Authenticate for step 2" - - sessionAttributes = identity.getSessionId().getSessionAttributes() - if (sessionAttributes == None) or not sessionAttributes.containsKey("gplus_user_uid"): - print "Google+ Authenticate for step 2. gplus_user_uid is empty" - return False - - gplusUserUid = sessionAttributes.get("gplus_user_uid") - passed_step1 = StringHelper.isNotEmptyString(gplusUserUid) - if (not passed_step1): - return False - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - userName = credentials.getUsername() - userPassword = credentials.getPassword() - - loggedIn = False - if (StringHelper.isNotEmptyString(userName) and StringHelper.isNotEmptyString(userPassword)): - loggedIn = authenticationService.authenticate(userName, userPassword) - - if (not loggedIn): - return False - - # Check if there is user which has gplusUserUid - # Avoid mapping Google account to more than one IDP account - foundUser = userService.getUserByAttribute("oxExternalUid", "gplus:" + gplusUserUid) - - if (foundUser == None): - # Add gplusUserUid to user one id UIDs - foundUser = userService.addUserAttribute(userName, "oxExternalUid", "gplus:" + gplusUserUid) - if (foundUser == None): - print "Google+ Authenticate for step 2. Failed to update current user" - return False - - postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) - print "Google+ Authenticate for step 2. postLoginResult: '%s'" % postLoginResult - - return postLoginResult - else: - foundUserName = foundUser.getUserId() - print "Google+ Authenticate for step 2. foundUserName: '%s'" % foundUserName - - if StringHelper.equals(userName, foundUserName): - postLoginResult = self.extensionPostLogin(configurationAttributes, foundUser) - print "Google+ Authenticate for step 2. postLoginResult: '%s'" % postLoginResult - - return postLoginResult - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - authenticationService = CdiUtil.bean(AuthenticationService) - - if (step == 1): - print "Google+ Prepare for step 1" - - currentClientSecrets = self.getCurrentClientSecrets(self.clientSecrets, configurationAttributes, requestParameters) - if (currentClientSecrets == None): - print "Google+ Prepare for step 1. Google+ client configuration is invalid" - return False - - identity.setWorkingParameter("gplus_client_id", currentClientSecrets["web"]["client_id"]) - identity.setWorkingParameter("gplus_client_secret", currentClientSecrets["web"]["client_secret"]) - - return True - elif (step == 2): - print "Google+ Prepare for step 2" - - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if (step == 2): - return Arrays.asList("gplus_user_uid") - - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - if (identity.isSetWorkingParameter("gplus_count_login_steps")): - return identity.getWorkingParameter("gplus_count_login_steps") - - return 2 - - def getPageForStep(self, configurationAttributes, step): - if (step == 1): - return "/auth/gplus/gpluslogin.xhtml" - - return "/auth/gplus/gpluspostlogin.xhtml" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - # TODO Revoke token - return True - - def loadClientSecrets(self, clientSecretsFile): - clientSecrets = None - - # Load certificate from file - f = open(clientSecretsFile, 'r') - try: - clientSecrets = json.loads(f.read()) - except: - print "Failed to load Google+ client secrets from file: '%s'" % clientSecrets - return None - finally: - f.close() - - return clientSecrets - - def getClientConfiguration(self, configurationAttributes, requestParameters): - # Get client configuration - if (configurationAttributes.containsKey("gplus_client_configuration_attribute")): - clientConfigurationAttribute = configurationAttributes.get("gplus_client_configuration_attribute").getValue2() - print "Google+ GetClientConfiguration. Using client attribute: '%s'" % clientConfigurationAttribute - - if (requestParameters == None): - return None - - clientId = None - - # Attempt to determine client_id from request - clientIdArray = requestParameters.get("client_id") - if (ArrayHelper.isNotEmpty(clientIdArray) and StringHelper.isNotEmptyString(clientIdArray[0])): - clientId = clientIdArray[0] - - # Attempt to determine client_id from event context - if (clientId == None): - identity = CdiUtil.bean(Identity) - if (identity.isSetWorkingParameter("sessionAttributes")): - clientId = identity.getSessionId().getSessionAttributes().get("client_id") - - if (clientId == None): - print "Google+ GetClientConfiguration. client_id is empty" - return None - - clientService = CdiUtil.bean(ClientService) - client = clientService.getClient(clientId) - if (client == None): - print "Google+ GetClientConfiguration. Failed to find client '%s' in local LDAP" % clientId - return None - - clientConfiguration = clientService.getCustomAttribute(client, clientConfigurationAttribute) - if ((clientConfiguration == None) or StringHelper.isEmpty(clientConfiguration.getValue())): - print "Google+ GetClientConfiguration. Client '%s' attribute '%s' is empty" % (clientId, clientConfigurationAttribute) - else: - print "Google+ GetClientConfiguration. Client '%s' attribute '%s' is '%s'" % (clientId, clientConfigurationAttribute, clientConfiguration) - return clientConfiguration - - return None - - def getCurrentClientSecrets(self, currentClientSecrets, configurationAttributes, requestParameters): - clientConfiguration = self.getClientConfiguration(configurationAttributes, requestParameters) - if (clientConfiguration == None): - return currentClientSecrets - - clientConfigurationValue = json.loads(clientConfiguration.getValue()) - - return clientConfigurationValue["gplus"] - - def getCurrentAttributesMapping(self, currentAttributesMapping, configurationAttributes, requestParameters): - clientConfiguration = self.getClientConfiguration(configurationAttributes, requestParameters) - if (clientConfiguration == None): - return currentAttributesMapping - - clientConfigurationValue = json.loads(clientConfiguration.getValue()) - - clientAttributesMapping = self.prepareAttributesMapping(clientConfigurationValue["gplus_remote_attributes_list"], clientConfigurationValue["gplus_local_attributes_list"]) - if (clientAttributesMapping == None): - print "Google+ GetCurrentAttributesMapping. Client attributes mapping is invalid. Using default one" - return currentAttributesMapping - - return clientAttributesMapping - - def prepareAttributesMapping(self, remoteAttributesList, localAttributesList): - remoteAttributesListArray = StringHelper.split(remoteAttributesList, ",") - if (ArrayHelper.isEmpty(remoteAttributesListArray)): - print "Google+ PrepareAttributesMapping. There is no attributes specified in remoteAttributesList property" - return None - - localAttributesListArray = StringHelper.split(localAttributesList, ",") - if (ArrayHelper.isEmpty(localAttributesListArray)): - print "Google+ PrepareAttributesMapping. There is no attributes specified in localAttributesList property" - return None - - if (len(remoteAttributesListArray) != len(localAttributesListArray)): - print "Google+ PrepareAttributesMapping. The number of attributes in remoteAttributesList and localAttributesList isn't equal" - return None - - attributeMapping = IdentityHashMap() - containsUid = False - i = 0 - count = len(remoteAttributesListArray) - while (i < count): - remoteAttribute = StringHelper.toLowerCase(remoteAttributesListArray[i]) - localAttribute = StringHelper.toLowerCase(localAttributesListArray[i]) - attributeMapping.put(remoteAttribute, localAttribute) - - if (StringHelper.equalsIgnoreCase(localAttribute, "uid")): - containsUid = True - - i = i + 1 - - if (not containsUid): - print "Google+ PrepareAttributesMapping. There is no mapping to mandatory 'uid' attribute" - return None - - return attributeMapping - - def getTokensByCode(self, currentClientSecrets, configurationAttributes, code): - tokenRequest = TokenRequest(GrantType.CLIENT_CREDENTIALS) - tokenRequest.setAuthenticationMethod(AuthenticationMethod.CLIENT_SECRET_POST) - tokenRequest.setCode(code) - tokenRequest.setAuthUsername(currentClientSecrets["web"]["client_id"]) - tokenRequest.setAuthPassword(currentClientSecrets["web"]["client_secret"]) - tokenRequest.setRedirectUri("postmessage") - tokenRequest.setGrantType(GrantType.AUTHORIZATION_CODE) - - tokenClient = TokenClient(currentClientSecrets["web"]["token_uri"]) - tokenClient.setRequest(tokenRequest) - - tokenResponse = tokenClient.exec() - if ((tokenResponse == None) or (tokenResponse.getStatus() != 200)): - return None - - return tokenResponse - - def getUserInfo(self, currentClientSecrets, configurationAttributes, accessToken): - userInfoClient = UserInfoClient("https://www.googleapis.com/plus/v1/people/me/openIdConnect") - - userInfoResponse = userInfoClient.execUserInfo(accessToken) - if ((userInfoResponse == None) or (userInfoResponse.getStatus() != 200)): - return None - - return userInfoResponse - - def extensionPostLogin(self, configurationAttributes, user): - if (self.extensionModule != None): - try: - postLoginResult = self.extensionModule.postLogin(configurationAttributes, user) - print "Google+ PostLogin result: '%s'" % postLoginResult - - return postLoginResult - except Exception, ex: - print "Google+ PostLogin. Failed to execute postLogin method" - print "Google+ PostLogin. Unexpected error:", ex - return False - except java.lang.Throwable, ex: - print "Google+ PostLogin. Failed to execute postLogin method" - ex.printStackTrace() - return False - - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/custom_script_entry.ldif b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/custom_script_entry.ldif deleted file mode 100644 index e1f3815e76d..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/custom_script_entry.ldif +++ /dev/null @@ -1,22 +0,0 @@ -dn: inum=@!1111!E521.2AE6,ou=scripts,o=gluu -objectClass: oxCustomScript -objectClass: top -displayName: gplus -gluuStatus: true -inum: @!1111!E521.2AE6 -oxConfigurationProperty: {"value1":"gplus_client_secrets_file","value2":"/et - c/certs/gplus_client_secrets.json","description":""} -oxConfigurationProperty: {"value1":"gplus_deployment_type","value2":"enroll" - ,"description":""} -oxConfigurationProperty: {"value1":"gplus_local_attributes_list","value2":"u - id, mail, givenName, sn, cn, preferredLanguage","description":""} -oxConfigurationProperty: {"value1":"gplus_remote_attributes_list","value2":" - email, email, given_name, family_name, given_name, locale","description":""} -oxLevel: 22 -oxModuleProperty: {"value1":"usage_type","value2":"interactive","description - ":""} -oxRevision: 1 -oxScript: -oxScriptType: person_authentication -programmingLanguage: python - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/gplus_client_secrets.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/gplus_client_secrets.json deleted file mode 100644 index 50c880ae891..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/sample/gplus_client_secrets.json +++ /dev/null @@ -1 +0,0 @@ -{"web":{"auth_uri":"https://accounts.google.com/o/oauth2/auth","client_secret":"","token_uri":"https://accounts.google.com/o/oauth2/token","client_email":"","redirect_uris":["https://myproductionurl.example.com/oauth2callback"],"client_x509_cert_url":"https://www.googleapis.com/robot/v1/metadata/x509/","client_id":"","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","javascript_origins":["https://myproductionurl.example.com"]}} \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/workflow.txt b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/workflow.txt deleted file mode 100644 index bf84de755f7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/gplus/workflow.txt +++ /dev/null @@ -1,39 +0,0 @@ -title Google+ oxAuth external authenticator plugin - -User Agent -> oxTrust: Access site protected by mod_ox/shibboleth - -oxTrust -> oxAuth: Redirect for user authentication - -oxAuth -> User Agent: Show login form with Google+ widget - -User Agent -> Google Server: Log into Google account - -Google Server -> User Agent: Returns OAuth2 code, id_token, etc.. - -User Agent -> oxAuth: Send OAuth2 code to Google+ oxAuth external authenticator - -oxAuth -> Google Server: Get OAuth2 id_token by code - -Google Server -> oxAuth: Returns id_token - -oxAuth -> oxAuth: Get Subject Identifier (Google persistent Id) from id_token - -oxAuth -> oxAuth: Check if there is IDP user with oxExternalUid: "gplus:" + google_persistent_id (Google persistent Id) - -oxAuth -> oxTrust: Allow access if user with gplus:google_persistent_id exists - -oxTrust -> User Agent: Allow access to resource - -oxAuth -> oxAuth : Start enrollment if user with gplus:google_persistent_id not exists - -oxAuth -> Google Server: Get OAuth2 user profile - -Google Server -> oxAuth: Returns OAuth2 claims - -oxAuth -> oxAuth: Add new user with gplus:google_persistent_id. Map user claims to user attributes. Set status of new user to "register". - -oxAuth -> oxTrust: Allow access to resource - -oxTrust -> oxTrust: Show user registration form - -oxTrust -> User Agent: Allow access to resource diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/alter_login.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/alter_login.xhtml deleted file mode 100644 index ce3cede6062..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/alter_login.xhtml +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
-
- - - - - -
-
- -
-
-
-
-
-

- - | - - - - - | - - - - - - | - - - - -

-
-
-
-
-
- - -
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst.py deleted file mode 100644 index 526dfff723b..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst.py +++ /dev/null @@ -1,98 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Jose Gonzalez (based on acr_routerauthenticator.py) -# -# NOTE: before using this script, see the accompanying readme file - -from io.jans.as.server.security import Identity -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService -from io.jans.util import StringHelper -from io.jans.service.cdi.util import CdiUtil - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Identifier First. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "Identifier First. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - print "Identifier First. isValidAuthenticationMethod called" - return False - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - print "Identifier First. getAlternativeAuthenticationMethod" - - identity = CdiUtil.bean(Identity) - user_name = identity.getCredentials().getUsername() - print "Identifier First. Inspecting user %s" % user_name - - attributes=identity.getSessionId().getSessionAttributes() - attributes.put("roUserName", user_name) - - acr = None - try: - userService = CdiUtil.bean(UserService) - foundUser = userService.getUserByAttribute("uid", user_name) - - if foundUser == None: - print "Identifier First. User does not exist" - return "" - - attr = configurationAttributes.get("acr_attribute").getValue2() - acr=foundUser.getAttribute(attr) - #acr="u2f" or "otp" or "twilio_sms", etc... - if acr == None: - acr = "basic" - except: - print "Identifier First. Error looking up user or his preferred method" - - print "Identifier First. new acr value %s" % acr - return acr - - def authenticate(self, configurationAttributes, requestParameters, step): - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - print "Identifier First. prepareForStep %s" % str(step) - return True - - def getExtraParametersForStep(self, configurationAttributes, step): - print "Identifier First. getExtraParametersForStep %s" % str(step) - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - print "Identifier First. getCountAuthenticationSteps called" - return 2 - - def getPageForStep(self, configurationAttributes, step): - print "Identifier First. getPageForStep called %s" % str(step) - if step == 1: - return "/auth/idfirst/idfirst_login.xhtml" - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - print "Identifier First. logout called" - return True diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst_login.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst_login.xhtml deleted file mode 100644 index 573ddb4dc2a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/idfirst/idfirst_login.xhtml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - -
- - - - -
- -
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/UpdateToken.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/UpdateToken.py deleted file mode 100644 index 93d7be40ba0..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/UpdateToken.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import print_function - -from io.jans.service.cdi.util import CdiUtil -from io.jans.model.custom.script.type.token import UpdateTokenType -from io.jans.oxauth.service import SessionIdService -import sys - - -class UpdateToken(UpdateTokenType): - - def __init__(self, currentTimeMillis): - """Construct class. - - Args: - currentTimeMillis (int): current time in miliseconds - """ - self.currentTimeMillis = currentTimeMillis - - @classmethod - def init(cls, customScript, configurationAttributes): - print("Update token obconnect script. Initializing ...") - print("Update token obconnect script. Initialized successfully") - - return True - - @classmethod - def destroy(cls, configurationAttributes): - print("Update token obconnect script. Destroying ...") - print("Update token obconnect script. Destroyed successfully") - return True - - @classmethod - def getApiVersion(cls): - return 11 - - # Returns boolean, true - indicates that script applied changes - # This method is called after adding headers and claims. Hence script can override them - # Note : - # jsonWebResponse - is JwtHeader, you can use any method to manipulate JWT - # context is reference of io.jans.oxauth.service.external.context.ExternalUpdateTokenContext (in https://github.com/GluuFederation/oxauth project, ) - @classmethod - def modifyIdToken(cls, jsonWebResponse, context): - print("Update token obconnect script. Modify idToken: %s" % jsonWebResponse) - try : - sessionIdService = CdiUtil.bean(SessionIdService) - print("session id from context - %s" % context.getGrant().getSessionDn().strip("oxId=")) - - sessionId = sessionIdService.getSessionByDn(context.getGrant().getSessionDn()) # fetch from persistence - if sessionId is None: - print("Session Id is none") - else: - print("session id -%s " % sessionId.getId()) - - print("session id -%s " % sessionId.getSessionAttributes()) - openbanking_intent_id = sessionId.getSessionAttributes().get("openbanking_intent_id") - acr = sessionId.getSessionAttributes().get("acr_ob") - - #jsonWebResponse.getHeader().setClaim("custom_header_name", "custom_header_value") - - #custom claims - jsonWebResponse.getClaims().setClaim("openbanking_intent_id", openbanking_intent_id) - jsonWebResponse.getClaims().setClaim("acr", acr) - - #regular claims - jsonWebResponse.getClaims().setClaim("sub", openbanking_intent_id) - - print("Update token script. After modify idToken: %s" % jsonWebResponse) - - return True - except Exception as e: - print("update token failure" , e, sys.exc_info()[1]) - return None diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/obconnectExternalAuthentication.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/obconnectExternalAuthentication.py deleted file mode 100644 index 9ea868e5bec..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/obconnectExternalAuthentication.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import print_function - -from java.util import Arrays -from io.jans.service.cdi.util import CdiUtil -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.jsf2.service import FacesService -from io.jans.oxauth.util import ServerUtil -from io.jans.oxauth.service import UserService, SessionIdService -# please uncomment the following line when you need AuthenticationService -#from io.jans.oxauth.service import AuthenticationService -from io.jans.oxauth.model.common import User -from java.lang import String - -from com.nimbusds.jose import EncryptionMethod; -from com.nimbusds.jose import JWEAlgorithm; -from com.nimbusds.jose import JWEHeader; -from com.nimbusds.jose import JWEObject; -from com.nimbusds.jose import Payload; -from com.nimbusds.jose.crypto import DirectDecrypter; -from com.nimbusds.jose.crypto import DirectEncrypter; -import time -import sys - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - """Construct class. - - Args: - currentTimeMillis (int): current time in miliseconds - """ - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - - if (not configurationAttributes.containsKey("sharedSecret")): - print("Obconnect. Initialization. Property sharedSecret is not specified") - return False - else: - self.sharedSecret = configurationAttributes.get("sharedSecret").getValue2() - if (not configurationAttributes.containsKey("hostname")): - print("Obconnect. Initialization. Property hostname is not specified") - return False - else: - self.hostname = configurationAttributes.get("hostname").getValue2() - - if (not configurationAttributes.containsKey("tpp_client_id")): - print("Obconnect. Initialization. Property tpp_client_id is not specified") - return False - else: - self.tpp_client_id = configurationAttributes.get("tpp_client_id").getValue2() - - if (not configurationAttributes.containsKey("client_name")): - print("Obconnect. Initialization. Property client_name is not specified") - return False - else: - self.client_name = configurationAttributes.get("client_name").getValue2() - - if (not configurationAttributes.containsKey("organisation_name")): - print("Obconnect. Initialization. Property organisation_name is not specified") - return False - else: - self.organisation_name = configurationAttributes.get("organisation_name").getValue2() - - if (not configurationAttributes.containsKey("expiry")): - print("Obconnect. Initialization. Property expiry is not specified") - return False - else: - self.expiry = configurationAttributes.get("expiry").getValue2() - - if (not configurationAttributes.containsKey("consent_app_server_name")): - print("Obconnect. Initialization. Property consent_app_server_name is not specified") - return False - else: - self.consent_app_server_name = configurationAttributes.get("consent_app_server_name").getValue2() - - return True - - @classmethod - def destroy(cls, configurationAttributes): - return True - - @classmethod - def getApiVersion(cls): - return 11 - - @classmethod - def getAuthenticationMethodClaims(cls, requestParameters): - return None - - @classmethod - def isValidAuthenticationMethod(cls, usageType, configurationAttributes): - return True - - @classmethod - def getAlternativeAuthenticationMethod(cls, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - print("Obconnect. Authenticate. Step %s " % step) - - sessionData = ServerUtil.getFirstValue(requestParameters, "sessionData") - - jweObject = JWEObject.parse(sessionData) - #Decrypt - jweObject.decrypt(DirectDecrypter((String(self.sharedSecret)).getBytes())) - - # Get the plain text - payload = jweObject.getPayload() - print("session payload - "+payload.toString()) - # A successful authorization will always return the `result` claim with login and consent details - if payload.toJSONObject().get("result") is not None : - resultObject = payload.toJSONObject().get("result") - if resultObject.get("login") is not None and resultObject.get("consent") is not None: - print("Obconnect .successful Authentication") - # question: What is the purpose of the following line? - #authenticationService = CdiUtil.bean(AuthenticationService) - - # TODO: create a dummy user and authenticate - newUser = User() - uid = "obconnect_"+str(int(time.time()*1000.0)) - newUser.setAttribute("uid",uid) - - #TODO: add a new parameter called expiry and set expiry time - # TODO: A clean up task should be written which will delete this record - userService = CdiUtil.bean(UserService) - userService.addUser(newUser, True) - # TODO: create a dummy user and authenticate - #logged_in = authenticationService.authenticate(uid) - - openbanking_intent_id = resultObject.get("login").get("account") - acr_ob = resultObject.get("login").get("acr") - - # add a few things in session - sessionIdService = CdiUtil.bean(SessionIdService) - sessionId = sessionIdService.getSessionId() # fetch from persistence - sessionId.getSessionAttributes().put("openbanking_intent_id", openbanking_intent_id) - sessionId.getSessionAttributes().put("acr_ob", acr_ob ) - - return True - print ("Obconnect.Unsuccessful authentication") - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - print("Obconnect. prepare for step... %s" % step) - scope = ServerUtil.getFirstValue(requestParameters, "scope") - print("An example of accessing parameter from the request - Scope: %s " % scope) - #extract intent id from request object which is an encoded JWT - request = ServerUtil.getFirstValue(requestParameters, "request") - - jweObject = JWEObject.parse(request) - #Decrypt - jweObject.decrypt(DirectDecrypter((String(self.sharedSecret)).getBytes())) - - # Get the plain text - print("jweobject : %s " % jweObject) - payload = jweObject.getPayload() - print("Obconnect.Request payload containing intent id- %s- " % payload) - print(" open intent id %s - " % payload.toJSONObject().get("openbanking_intent_id")) - - # A successful authorization will always return the `result` claim with login and consent details - if payload.toJSONObject().get("openbanking_intent_id") is not None: - print("1.") - openbanking_intent_id = str(payload.toJSONObject().get("openbanking_intent_id")) - print("openbanking_intent_id %s" % openbanking_intent_id) - #sessionId = CdiUtil.bean(SessionIdService).getSessionId() - sessionId = "1231231231231" - print("sessionID : %s " % sessionId) - redirectURL = self.getRedirectURL (openbanking_intent_id, sessionId) - - print("Obconnect. Redirecting to ... %s " % redirectURL) - facesService = CdiUtil.bean(FacesService) - facesService.redirectToExternalURL(redirectURL) - return True - - print("Obconnect. Call to Gluu's /authorize endpoint should contain openbanking_intent_id as an encoded JWT") - return False - - @classmethod - def getCountAuthenticationSteps(cls, configurationAttributes): - return 1 - - @classmethod - def getNextStep(cls, configurationAttributes, requestParameters, step): - return -1 - - @classmethod - def getPageForStep(cls, configurationAttributes, step): - print("Obconnect. getPageForStep... %s" % step) - if step == 1: - return "/auth/redirect.xhtml" - - return "" - - @classmethod - def getExtraParametersForStep(cls, configurationAttributes, step): - return Arrays.asList("openbanking_intent_id", "acr_ob") - - @classmethod - def logout(cls, configurationAttributes, requestParameters): - return True - - @classmethod - def buildSessionIdObject(cls, hostname, intent_id_value,unique_identifier_for_session_object, - tpp_client_id, client_name,organisation_name, expiry) : - - sessionIdObject = "{\"returnTo\": \"" + hostname + "/oxauth/postlogin.htm" + \ - "\",\"prompt\": {\"name\": \"login\", \"details\" : { \"openbanking_intent_id\" : {" + \ - "\"value\": \"" + intent_id_value + "\", \"essential\" : \"true\"}}}, "+ " \"uid\" : \"" + \ - unique_identifier_for_session_object + "\" , \"params\" : { \"client_id\": \"" + \ - tpp_client_id+ "\", \"scope\": \"openid accounts\", \"claims\": " +\ - "\"{\\\"userinfo\\\":{\\\"openbanking_intent_id\\\":{\\\"value\\\":\\\"" + intent_id_value + \ - "\\\",\\\"essential\\\":true}},\\\"id_token\\\":{\\\"openbanking_intent_id\\\":{\\\"value\\\":\\\"" + \ - intent_id_value + "\\\",\\\"essential\\\":true},\\\"acr\\\":{\\\"values\\\":[\\\"urn:openbanking:psd2:sca\\\"\ - ,\\\"urn:openbanking:psd2:ca\\\"],\\\"essential\\\":true}}}\""+ "}, \"exp\" : " + expiry + \ - ", \"client\": { \"client_name\": \"" + client_name + "\",\"org_name\" : \""+ organisation_name + "\"}}" - - print("Obconnect. sessionIdObject: %s " % sessionIdObject) - return sessionIdObject - - def getRedirectURL (self, openbanking_intent_id, sessionID): - - #TODO: this is not required - unique_identifier_for_session_object = "12345" - - try : - # Create the header - header = JWEHeader(JWEAlgorithm.DIR, EncryptionMethod.A256GCM) - - # Create the payload - payloadString = self.buildSessionIdObject(self.hostname, openbanking_intent_id, unique_identifier_for_session_object, - self.tpp_client_id, self.client_name, self.organisation_name, self.expiry) - print("Payload String "+ payloadString) - payload = Payload(payloadString ) - - # Create the JWE object and encrypt it - jweObject = JWEObject(header, payload) - jweObject.encrypt( DirectEncrypter((String(self.sharedSecret)).getBytes())) - - # Serialise to compact JOSE form... - jweString = jweObject.serialize() - print("Redirect URL -->"+self.consent_app_server_name+"/?sessionData="+jweString) - return self.consent_app_server_name+"/?sessionData="+jweString - - except Exception as e: - print("Obconnect. Failed to build redirect URL -", e, sys.exc_info()[1]) - return None diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/redirect.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/redirect.xhtml deleted file mode 100644 index f39ade73837..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/obconnect/redirect.xhtml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidlogin.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidlogin.xhtml deleted file mode 100644 index 2b8cef3737f..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidlogin.xhtml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - #{msgs['oneidlogin.title']} - - - - - - - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidpostlogin.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidpostlogin.xhtml deleted file mode 100644 index 03b59826df0..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/oneid/oneidpostlogin.xhtml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - #{msgs['oneidlogin.title']} - - - - - - - - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/Properties description.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/Properties description.md deleted file mode 100644 index 6e89b62ea40..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/Properties description.md +++ /dev/null @@ -1,25 +0,0 @@ -Script contents [here](https://github.com/JanssenProject/jans/jans-linux-setup/static/extension/person_authentication/OtpExternalAuthenticator.py) - -This is a person authentication script for jans-auth-server which enables one-time password for user authentication. - -The module has a few properties: - -1) otp_type - It's mandatory property. It's specify OTP mode: HOTP/ TOTP. - Allowed values: hotp/totp - Example: hotp - -2) issuer - It's mandatory property. It's company name. - Example: Janssen Inc - -3) otp_conf_file - It's mandatory property. It's specify path to OTP configuration JSON file. - Example: /etc/certs/otp_configuration.json - -4) label - It's label inside QR code. It's optional property. - Example: Janssen OTP - -5) qr_options - Specify width and height of QR image. It's optional property. - Example: qr_options: { width: 400, height: 400 } - -6) registration_uri - It's URL to page where user can register new account. It's optional property. - Example: https://ce-dev.jans.org/identity/register - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/img/gluu_otp_integration_authentication_workflow.png b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/img/gluu_otp_integration_authentication_workflow.png deleted file mode 100644 index 4397d9d7b0805c341510b0168c6f6aaa738462fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64598 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 H!wdflq>)Ik diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/_remote.repositories b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/_remote.repositories deleted file mode 100644 index 095939909cc..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/_remote.repositories +++ /dev/null @@ -1,6 +0,0 @@ -#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. -#Mon Sep 26 13:13:34 MSK 2016 -oath-otp-keyprovisioning-0.0.1-SNAPSHOT.pom>= -oath-otp-keyprovisioning-0.0.1-SNAPSHOT-javadoc.jar>= -oath-otp-keyprovisioning-0.0.1-SNAPSHOT.jar>= -oath-otp-keyprovisioning-0.0.1-SNAPSHOT-sources.jar>= diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index db499fc99c7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - com.lochbridge.oath - oath-otp-keyprovisioning - 0.0.1-SNAPSHOT - - - true - - 20160926101334 - - - javadoc - jar - 0.0.1-SNAPSHOT - 20160926101334 - - - sources - jar - 0.0.1-SNAPSHOT - 20160926101334 - - - jar - 0.0.1-SNAPSHOT - 20160926101334 - - - pom - 0.0.1-SNAPSHOT - 20160926101334 - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT-javadoc.jar b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/0.0.1-SNAPSHOT/oath-otp-keyprovisioning-0.0.1-SNAPSHOT-javadoc.jar deleted file mode 100644 index 65b92f445fefe553438c05c799a39fc983798329..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71430 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 - 4.0.0 - - com.lochbridge.oath - oath-parent - 0.0.1-SNAPSHOT - - oath-otp-keyprovisioning - OATH OTP Key Provisioning - A module for providing OTP key provisioning support. - - - 3.1.0 - - - - - com.google.guava - guava - - - - - com.google.zxing - core - ${com.google.zxing.version} - - - com.google.zxing - javase - ${com.google.zxing.version} - - - - com.lochbridge.oath - oath-otp - 0.0.1-SNAPSHOT - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/maven-metadata-local.xml deleted file mode 100644 index c7f4b52aff0..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp-keyprovisioning/maven-metadata-local.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - com.lochbridge.oath - oath-otp-keyprovisioning - - - 0.0.1-SNAPSHOT - - 20160926101334 - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/_remote.repositories b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/_remote.repositories deleted file mode 100644 index 865f16cf7b5..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/_remote.repositories +++ /dev/null @@ -1,6 +0,0 @@ -#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. -#Mon Sep 26 13:13:32 MSK 2016 -oath-otp-0.0.1-SNAPSHOT.jar>= -oath-otp-0.0.1-SNAPSHOT-sources.jar>= -oath-otp-0.0.1-SNAPSHOT.pom>= -oath-otp-0.0.1-SNAPSHOT-javadoc.jar>= diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index cfd6fa0c9cd..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - com.lochbridge.oath - oath-otp - 0.0.1-SNAPSHOT - - - true - - 20160926101332 - - - javadoc - jar - 0.0.1-SNAPSHOT - 20160926101332 - - - sources - jar - 0.0.1-SNAPSHOT - 20160926101332 - - - jar - 0.0.1-SNAPSHOT - 20160926101332 - - - pom - 0.0.1-SNAPSHOT - 20160926101332 - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-javadoc.jar b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-javadoc.jar deleted file mode 100644 index 9eca484ff18c15ef82507ff7d9cdc990d9badc37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68069 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%0Dk>H?Rm^Wu=}o9I}P+gErXA*gMU` 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

2$v43epbLvGpRx=R)`Kj2me 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 diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-sources.jar b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/0.0.1-SNAPSHOT/oath-otp-0.0.1-SNAPSHOT-sources.jar deleted file mode 100644 index 03c2aabd55df7b7266105ed3f0e04ff7454a48e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13536 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 fzYP7UgFnNJG7$FB&> - 4.0.0 - - com.lochbridge.oath - oath-parent - 0.0.1-SNAPSHOT - - oath-otp - OATH OTP - A module for generating and validating OTPs. - - - - com.google.guava - guava - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/maven-metadata-local.xml deleted file mode 100644 index e2477503be5..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-otp/maven-metadata-local.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - com.lochbridge.oath - oath-otp - - - 0.0.1-SNAPSHOT - - 20160926101332 - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/_remote.repositories b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/_remote.repositories deleted file mode 100644 index d0af97df1ca..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/_remote.repositories +++ /dev/null @@ -1,3 +0,0 @@ -#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. -#Mon Sep 26 13:13:30 MSK 2016 -oath-parent-0.0.1-SNAPSHOT.pom>= diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/maven-metadata-local.xml deleted file mode 100644 index 8ebf18a35f6..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/maven-metadata-local.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - com.lochbridge.oath - oath-parent - 0.0.1-SNAPSHOT - - - true - - 20160926101330 - - - pom - 0.0.1-SNAPSHOT - 20160926101330 - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/oath-parent-0.0.1-SNAPSHOT.pom b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/oath-parent-0.0.1-SNAPSHOT.pom deleted file mode 100644 index ee4048d1aca..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/0.0.1-SNAPSHOT/oath-parent-0.0.1-SNAPSHOT.pom +++ /dev/null @@ -1,182 +0,0 @@ - - 4.0.0 - com.lochbridge.oath - oath-parent - 0.0.1-SNAPSHOT - pom - OATH Project - https://github.com/johnnymongiat/oath - - OATH provides components for building one-time password authentication systems. - - - - UTF-8 - UTF-8 - 18.0 - - - - - Johnny Mongiat - johnnymongiat@gmail.com - America/Montreal - - committer - - - - - - scm:git:https://github.com/johnnymongiat/oath.git - scm:git:https://github.com/johnnymongiat/oath.git - https://github.com/johnnymongiat/oath.git - - - - github - https://github.com/johnnymongiat/oath/issues - - - - Travis CI - https://travis-ci.org/johnnymongiat/oath - - - - - The MIT License (MIT) - http://opensource.org/licenses/MIT - manual - - - - - - junit - junit - 4.11 - test - - - org.mockito - mockito-core - 1.9.5 - test - - - - - - - com.google.guava - guava - ${guava.version} - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-source-plugin - 2.3 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - ${javadoc.doclint.none} - - - - attach-javadocs - - jar - - - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.5 - - - - true - - - - - - org.codehaus.mojo - cobertura-maven-plugin - 2.6 - - - xml - html - - true - - - - org.eluder.coveralls - coveralls-maven-plugin - 3.0.1 - - - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.7 - - true - true - - - - - - - oath-otp - oath-otp-keyprovisioning - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/maven-metadata-local.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/maven-metadata-local.xml deleted file mode 100644 index e496352c0f1..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/repository/com/lochbridge/oath/oath-parent/maven-metadata-local.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - com.lochbridge.oath - oath-parent - - - 0.0.1-SNAPSHOT - - 20160926101330 - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sample/otp_configuration.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sample/otp_configuration.json deleted file mode 100644 index 43b27d1c9f7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sample/otp_configuration.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "htop":{ - "keyLength":20, - "digits":6, - "lookAheadWindow":1 - }, - "totp":{ - "keyLength":20, - "digits":6, - "timeStep":30, - "hmacShaAlgorithm": "sha1" - } -} diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sequence_diagram.txt b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sequence_diagram.txt deleted file mode 100644 index f03514bb36e..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/otp/sequence_diagram.txt +++ /dev/null @@ -1,31 +0,0 @@ -Title OTP enrollment/authentication workflow - -Person->Browser: Open RP URL -Browser->RP: Protected resource -RP->Gluu Server: Start AuthZ & AuthN -OTP Script->OTP Script: Verify user/password - -alt: User enrollment - OTP Script->OTP Script: Check if person not issued OTP key already - OTP Script->Browser: Render otpauth QR code with OTP key - Person->OTP comp. auth.: Scan QR code - OTP comp. auth.->Person: New one time password - Person->Browser: Enter one time password - Browser->OTP Script: - OTP Script->OTP Script: Validate one time password - OTP Script->OTP Script: Strore OTP key in user entry - OTP Script->Gluu Server: User pass enrollment -else User authentication - OTP Script->OTP Script: Check if person issued OTP key already - OTP comp. auth.->Person: New one time password - Person->Browser: Enter one time password - Browser->OTP Script: - OTP Script->OTP Script: Validate one time password - OTP Script->Gluu Server: User pass enrollment -end - -Gluu Server->Browser: Return code -Browser->RP: Return code - -RP->Gluu Server: Request tokens -RP->Gluu Server: Request user_info diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/PassportExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/PassportExternalAuthenticator.py deleted file mode 100644 index 01bc629af60..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/PassportExternalAuthenticator.py +++ /dev/null @@ -1,631 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Jose Gonzalez -# Author: Yuriy Movchan -# -from io.jans.jsf2.service import FacesService -from io.jans.jsf2.message import FacesMessages - -from org.gluu.oxauth.model.common import User, WebKeyStorage -from org.gluu.oxauth.model.configuration import AppConfiguration -from org.gluu.oxauth.model.crypto import CryptoProviderFactory -from org.gluu.oxauth.model.jwt import Jwt, JwtClaimName -from org.gluu.oxauth.model.util import Base64Util -from io.jans.as.server.service import AppInitializer, AuthenticationService -from io.jans.as.server.service.common import UserService, EncryptionService -from io.jans.as.server.service.net import HttpService -from io.jans.as.server.security import Identity -from io.jans.as.server.util import ServerUtil -from org.gluu.config.oxtrust import LdapOxPassportConfiguration -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.orm import PersistenceEntryManager -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper -from java.util import ArrayList, Arrays, Collections - -from jakarta.faces.application import FacesMessage -from jakarta.faces.context import FacesContext - -import json -import sys -import datetime - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Passport. init called" - - self.extensionModule = self.loadExternalModule(configurationAttributes.get("extension_module")) - extensionResult = self.extensionInit(configurationAttributes) - if extensionResult != None: - return extensionResult - - print "Passport. init. Behaviour is social" - success = self.processKeyStoreProperties(configurationAttributes) - - if success: - self.providerKey = "provider" - self.customAuthzParameter = self.getCustomAuthzParameter(configurationAttributes.get("authz_req_param_provider")) - self.passportDN = self.getPassportConfigDN() - print "Passport. init. Initialization success" - else: - print "Passport. init. Initialization failed" - return success - - - def destroy(self, configurationAttributes): - print "Passport. destroy called" - return True - - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - - def authenticate(self, configurationAttributes, requestParameters, step): - - extensionResult = self.extensionAuthenticate(configurationAttributes, requestParameters, step) - if extensionResult != None: - return extensionResult - - print "Passport. authenticate for step %s called" % str(step) - identity = CdiUtil.bean(Identity) - - # Loading self.registeredProviders in case passport destroyed - if not hasattr(self,'registeredProviders'): - print "Passport. Fetching registered providers." - self.parseProviderConfigs() - - if step == 1: - # Get JWT token - jwt_param = ServerUtil.getFirstValue(requestParameters, "user") - - if jwt_param != None: - print "Passport. authenticate for step 1. JWT user profile token found" - - # Parse JWT and validate - jwt = Jwt.parse(jwt_param) - if not self.validSignature(jwt): - return False - - if self.jwtHasExpired(jwt): - return False - - (user_profile, jsonp) = self.getUserProfile(jwt) - if user_profile == None: - return False - - sessionAttributes = identity.getSessionId().getSessionAttributes() - self.skipProfileUpdate = StringHelper.equalsIgnoreCase(sessionAttributes.get("skipPassportProfileUpdate"), "true") - - return self.attemptAuthentication(identity, user_profile, jsonp) - - #See passportlogin.xhtml - provider = ServerUtil.getFirstValue(requestParameters, "loginForm:provider") - if StringHelper.isEmpty(provider): - - #it's username + passw auth - print "Passport. authenticate for step 1. Basic authentication detected" - logged_in = False - - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - authenticationService = CdiUtil.bean(AuthenticationService) - logged_in = authenticationService.authenticate(user_name, user_password) - - print "Passport. authenticate for step 1. Basic authentication returned: %s" % logged_in - return logged_in - - elif provider in self.registeredProviders: - #it's a recognized external IDP - identity.setWorkingParameter("selectedProvider", provider) - print "Passport. authenticate for step 1. Retrying step 1" - #see prepareForStep (step = 1) - return True - - if step == 2: - mail = ServerUtil.getFirstValue(requestParameters, "loginForm:email") - jsonp = identity.getWorkingParameter("passport_user_profile") - - if mail == None: - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email was missing in user profile") - elif jsonp != None: - # Completion of profile takes place - user_profile = json.loads(jsonp) - user_profile["mail"] = [ mail ] - - return self.attemptAuthentication(identity, user_profile, jsonp) - - print "Passport. authenticate for step 2. Failed: expected mail value in HTTP request and json profile in session" - return False - - - def prepareForStep(self, configurationAttributes, requestParameters, step): - - extensionResult = self.extensionPrepareForStep(configurationAttributes, requestParameters, step) - if extensionResult != None: - return extensionResult - - print "Passport. prepareForStep called %s" % str(step) - identity = CdiUtil.bean(Identity) - - if step == 1: - #re-read the strategies config (for instance to know which strategies have enabled the email account linking) - self.parseProviderConfigs() - identity.setWorkingParameter("externalProviders", json.dumps(self.registeredProviders)) - - providerParam = self.customAuthzParameter - url = None - - sessionAttributes = identity.getSessionId().getSessionAttributes() - self.skipProfileUpdate = StringHelper.equalsIgnoreCase(sessionAttributes.get("skipPassportProfileUpdate"), "true") - - #this param could have been set previously in authenticate step if current step is being retried - provider = identity.getWorkingParameter("selectedProvider") - if provider != None: - url = self.getPassportRedirectUrl(provider) - identity.setWorkingParameter("selectedProvider", None) - - elif providerParam != None: - paramValue = sessionAttributes.get(providerParam) - - if paramValue != None: - print "Passport. prepareForStep. Found value in custom param of authorization request: %s" % paramValue - provider = self.getProviderFromJson(paramValue) - - if provider == None: - print "Passport. prepareForStep. A provider value could not be extracted from custom authorization request parameter" - elif not provider in self.registeredProviders: - print "Passport. prepareForStep. Provider '%s' not part of known configured IDPs/OPs" % provider - else: - url = self.getPassportRedirectUrl(provider) - - if url == None: - print "Passport. prepareForStep. A page to manually select an identity provider will be shown" - else: - facesService = CdiUtil.bean(FacesService) - facesService.redirectToExternalURL(url) - - return True - - - def getExtraParametersForStep(self, configurationAttributes, step): - print "Passport. getExtraParametersForStep called" - if step == 1: - return Arrays.asList("selectedProvider", "externalProviders") - elif step == 2: - return Arrays.asList("passport_user_profile") - return None - - - def getCountAuthenticationSteps(self, configurationAttributes): - print "Passport. getCountAuthenticationSteps called" - identity = CdiUtil.bean(Identity) - if identity.getWorkingParameter("passport_user_profile") != None: - return 2 - return 1 - - - def getPageForStep(self, configurationAttributes, step): - print "Passport. getPageForStep called" - - extensionResult = self.extensionGetPageForStep(configurationAttributes, step) - if extensionResult != None: - return extensionResult - - if step == 1: - return "/auth/passport/passportlogin.xhtml" - return "/auth/passport/passportpostlogin.xhtml" - - - def getNextStep(self, configurationAttributes, requestParameters, step): - - if step == 1: - identity = CdiUtil.bean(Identity) - provider = identity.getWorkingParameter("selectedProvider") - if provider != None: - return 1 - - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - -# Extension module related functions - - def extensionInit(self, configurationAttributes): - - if self.extensionModule == None: - return None - return self.extensionModule.init(configurationAttributes) - - - def extensionAuthenticate(self, configurationAttributes, requestParameters, step): - - if self.extensionModule == None: - return None - return self.extensionModule.authenticate(configurationAttributes, requestParameters, step) - - - def extensionPrepareForStep(self, configurationAttributes, requestParameters, step): - - if self.extensionModule == None: - return None - return self.extensionModule.prepareForStep(configurationAttributes, requestParameters, step) - - - def extensionGetPageForStep(self, configurationAttributes, step): - - if self.extensionModule == None: - return None - return self.extensionModule.getPageForStep(configurationAttributes, step) - -# Initalization routines - - def loadExternalModule(self, simpleCustProperty): - - if simpleCustProperty != None: - print "Passport. loadExternalModule. Loading passport extension module..." - moduleName = simpleCustProperty.getValue2() - try: - module = __import__(moduleName) - return module - except: - print "Passport. loadExternalModule. Failed to load module %s" % moduleName - print "Exception: ", sys.exc_info()[1] - print "Passport. loadExternalModule. Flow will be driven entirely by routines of main passport script" - return None - - - def processKeyStoreProperties(self, attrs): - file = attrs.get("key_store_file") - password = attrs.get("key_store_password") - - if file != None and password != None: - file = file.getValue2() - password = password.getValue2() - - if StringHelper.isNotEmpty(file) and StringHelper.isNotEmpty(password): - self.keyStoreFile = file - self.keyStorePassword = password - return True - - print "Passport. readKeyStoreProperties. Properties key_store_file or key_store_password not found or empty" - return False - - - def getCustomAuthzParameter(self, simpleCustProperty): - - customAuthzParameter = None - if simpleCustProperty != None: - prop = simpleCustProperty.getValue2() - if StringHelper.isNotEmpty(prop): - customAuthzParameter = prop - - if customAuthzParameter == None: - print "Passport. getCustomAuthzParameter. No custom param for OIDC authz request in script properties" - print "Passport. getCustomAuthzParameter. Passport flow cannot be initiated by doing an OpenID connect authorization request" - else: - print "Passport. getCustomAuthzParameter. Custom param for OIDC authz request in script properties: %s" % customAuthzParameter - - return customAuthzParameter - -# Configuration parsing - - def getPassportConfigDN(self): - - f = open('/etc/gluu/conf/jans.properties', 'r') - for line in f: - prop = line.split("=") - if prop[0] == "oxpassport_ConfigurationEntryDN": - prop.pop(0) - break - - f.close() - return "=".join(prop).strip() - - - def parseAllProviders(self): - - registeredProviders = {} - print "Passport. parseAllProviders. Adding providers" - entryManager = CdiUtil.bean(PersistenceEntryManager) - - config = LdapOxPassportConfiguration() - config = entryManager.find(config.getClass(), self.passportDN).getPassportConfiguration() - config = config.getProviders() if config != None else config - - if config != None and len(config) > 0: - for prvdetails in config: - if prvdetails.isEnabled(): - registeredProviders[prvdetails.getId()] = { - "emailLinkingSafe": prvdetails.isEmailLinkingSafe(), - "requestForEmail" : prvdetails.isRequestForEmail(), - "logo_img": prvdetails.getLogoImg(), - "displayName": prvdetails.getDisplayName(), - "type": prvdetails.getType() - } - - return registeredProviders - - - def parseProviderConfigs(self): - - registeredProviders = {} - try: - registeredProviders = self.parseAllProviders() - toRemove = [] - - for provider in registeredProviders: - if registeredProviders[provider]["type"] == "saml": - toRemove.append(provider) - else: - registeredProviders[provider]["saml"] = False - - for provider in toRemove: - registeredProviders.pop(provider) - - if len(registeredProviders.keys()) > 0: - print "Passport. parseProviderConfigs. Configured providers:", registeredProviders - else: - print "Passport. parseProviderConfigs. No providers registered yet" - except: - print "Passport. parseProviderConfigs. An error occurred while building the list of supported authentication providers", sys.exc_info()[1] - - self.registeredProviders = registeredProviders - -# Auxiliary routines - - def getProviderFromJson(self, providerJson): - - provider = None - try: - obj = json.loads(Base64Util.base64urldecodeToString(providerJson)) - provider = obj[self.providerKey] - except: - print "Passport. getProviderFromJson. Could not parse provided Json string. Returning None" - - return provider - - - def getPassportRedirectUrl(self, provider): - - # provider is assumed to exist in self.registeredProviders - url = None - try: - facesContext = CdiUtil.bean(FacesContext) - tokenEndpoint = "https://%s/passport/token" % facesContext.getExternalContext().getRequest().getServerName() - - httpService = CdiUtil.bean(HttpService) - httpclient = httpService.getHttpsClient() - - print "Passport. getPassportRedirectUrl. Obtaining token from passport at %s" % tokenEndpoint - resultResponse = httpService.executeGet(httpclient, tokenEndpoint, Collections.singletonMap("Accept", "text/json")) - httpResponse = resultResponse.getHttpResponse() - bytes = httpService.getResponseContent(httpResponse) - - response = httpService.convertEntityToString(bytes) - print "Passport. getPassportRedirectUrl. Response was %s" % httpResponse.getStatusLine().getStatusCode() - - tokenObj = json.loads(response) - url = "/passport/auth/%s/%s" % (provider, tokenObj["token_"]) - except: - print "Passport. getPassportRedirectUrl. Error building redirect URL: ", sys.exc_info()[1] - - return url - - - def validSignature(self, jwt): - - print "Passport. validSignature. Checking JWT token signature" - valid = False - - try: - appConfiguration = AppConfiguration() - appConfiguration.setWebKeysStorage(WebKeyStorage.KEYSTORE) - appConfiguration.setKeyStoreFile(self.keyStoreFile) - appConfiguration.setKeyStoreSecret(self.keyStorePassword) - appConfiguration.setKeyRegenerationEnabled(False) - - cryptoProvider = CryptoProviderFactory.getCryptoProvider(appConfiguration) - valid = cryptoProvider.verifySignature(jwt.getSigningInput(), jwt.getEncodedSignature(), jwt.getHeader().getKeyId(), - None, None, jwt.getHeader().getSignatureAlgorithm()) - except: - print "Exception: ", sys.exc_info()[1] - - print "Passport. validSignature. Validation result was %s" % valid - return valid - - - def jwtHasExpired(self, jwt): - # Check if jwt has expired - jwt_claims = jwt.getClaims() - try: - exp_date_timestamp = float(jwt_claims.getClaimAsString(JwtClaimName.EXPIRATION_TIME)) - exp_date = datetime.datetime.fromtimestamp(exp_date_timestamp) - hasExpired = exp_date < datetime.datetime.now() - except: - print "Exception: The JWT does not have '%s' attribute" % JwtClaimName.EXPIRATION_TIME - return False - - return hasExpired - - - def getUserProfile(self, jwt): - jwt_claims = jwt.getClaims() - user_profile_json = None - - try: - user_profile_json = CdiUtil.bean(EncryptionService).decrypt(jwt_claims.getClaimAsString("data")) - user_profile = json.loads(user_profile_json) - except: - print "Passport. getUserProfile. Problem obtaining user profile json representation" - - return (user_profile, user_profile_json) - - - def attemptAuthentication(self, identity, user_profile, user_profile_json): - - uidKey = "uid" - if not self.checkRequiredAttributes(user_profile, [uidKey, self.providerKey]): - return False - - provider = user_profile[self.providerKey] - if not provider in self.registeredProviders: - print "Passport. attemptAuthentication. Identity Provider %s not recognized" % provider - return False - - uid = user_profile[uidKey][0] - externalUid = "passport-%s:%s" % (provider, uid) - - userService = CdiUtil.bean(UserService) - userByUid = userService.getUserByAttribute("oxExternalUid", externalUid, True) - - email = None - if "mail" in user_profile: - email = user_profile["mail"] - if len(email) == 0: - email = None - else: - email = email[0] - user_profile["mail"] = [ email ] - - if email == None and self.registeredProviders[provider]["requestForEmail"]: - print "Passport. attemptAuthentication. Email was not received" - - if userByUid != None: - # This avoids asking for the email over every login attempt - email = userByUid.getAttribute("mail") - if email != None: - print "Passport. attemptAuthentication. Filling missing email value with %s" % email - user_profile["mail"] = [ email ] - - if email == None: - # Store user profile in session and abort this routine - identity.setWorkingParameter("passport_user_profile", user_profile_json) - return True - - userByMail = None if email == None else userService.getUserByAttribute("mail", email) - - # Determine if we should add entry, update existing, or deny access - doUpdate = False - doAdd = False - if userByUid != None: - print "User with externalUid '%s' already exists" % externalUid - if userByMail == None: - doUpdate = True - else: - if userByMail.getUserId() == userByUid.getUserId(): - doUpdate = True - else: - print "Users with externalUid '%s' and mail '%s' are different. Access will be denied. Impersonation attempt?" % (externalUid, email) - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email value corresponds to an already existing provisioned account") - else: - if userByMail == None: - doAdd = True - elif self.registeredProviders[provider]["emailLinkingSafe"]: - - tmpList = userByMail.getAttributeValues("oxExternalUid") - tmpList = ArrayList() if tmpList == None else ArrayList(tmpList) - tmpList.add(externalUid) - userByMail.setAttribute("oxExternalUid", tmpList, True) - - userByUid = userByMail - print "External user supplying mail %s will be linked to existing account '%s'" % (email, userByMail.getUserId()) - doUpdate = True - else: - print "An attempt to supply an email of an existing user was made. Turn on 'emailLinkingSafe' if you want to enable linking" - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email value corresponds to an already existing account. If you already have a username and password use those instead of an external authentication site to get access.") - - username = None - try: - if doUpdate: - username = userByUid.getUserId() - print "Passport. attemptAuthentication. Updating user %s" % username - self.updateUser(userByUid, user_profile, userService) - elif doAdd: - print "Passport. attemptAuthentication. Creating user %s" % externalUid - newUser = self.addUser(externalUid, user_profile, userService) - username = newUser.getUserId() - except: - print "Exception: ", sys.exc_info()[1] - print "Passport. attemptAuthentication. Authentication failed" - return False - - if username == None: - print "Passport. attemptAuthentication. Authentication attempt was rejected" - return False - else: - logged_in = CdiUtil.bean(AuthenticationService).authenticate(username) - print "Passport. attemptAuthentication. Authentication for %s returned %s" % (username, logged_in) - return logged_in - - - def setMessageError(self, severity, msg): - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.clear() - facesMessages.add(severity, msg) - - - def checkRequiredAttributes(self, profile, attrs): - - for attr in attrs: - if (not attr in profile) or len(profile[attr]) == 0: - print "Passport. checkRequiredAttributes. Attribute '%s' is missing in profile" % attr - return False - return True - - - def addUser(self, externalUid, profile, userService): - - newUser = User() - #Fill user attrs - newUser.setAttribute("oxExternalUid", externalUid, True) - self.fillUser(newUser, profile) - newUser = userService.addUser(newUser, True) - return newUser - - - def updateUser(self, foundUser, profile, userService): - - # when this is false, there might still some updates taking place (e.g. not related to profile attrs released by external provider) - if (not self.skipProfileUpdate): - self.fillUser(foundUser, profile) - userService.updateUser(foundUser) - - - def fillUser(self, foundUser, profile): - - for attr in profile: - # "provider" is disregarded if part of mapping - if attr != self.providerKey: - values = profile[attr] - print "%s = %s" % (attr, values) - foundUser.setAttribute(attr, values) - - if attr == "mail": - oxtrustMails = [] - for mail in values: - oxtrustMails.append('{"value":"%s","primary":false}' % mail) - foundUser.setAttribute("oxTrustEmail", oxtrustMails) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/README.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/README.md deleted file mode 100644 index f6057707858..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/README.md +++ /dev/null @@ -1,10 +0,0 @@ -Passport is a person authentication module for oxAuth that enables [Google+ Authentication](https://www.google.com), [Twitter Authentication](https://www.twitter.com), [Facebook Authentication](https://www.facebook.com) etc. for user authentication. - -The module has a few properties: - - 1) generic_remote_attributes_list - It's mandatory property. Comma separated list of attribute names. Specify list of User claims(attributes) which script should use to map to local attributes. The count of attributes in this property should be equal to count attributes in generic_local_attributes_list property. -Example: `username, email, name, name, givenName, familyName, provider` - - 2) generic_local_attributes_list - It's mandatory property. Comma separated list of attribute names. Specify list of local attributes mapped from passport userInfo response. The count of attributes in this property should be equal to count attributes in generic_remote_attributes_list property. Local attributes list should contains next mandatory attributes: uid, mail, givenName, sn, cn. -Example: `uid, mail, cn, displayName, givenName, sn, provider` - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/sample/passport_script_entry.ldif b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/sample/passport_script_entry.ldif deleted file mode 100644 index 7142616ea58..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/passport/sample/passport_script_entry.ldif +++ /dev/null @@ -1,16 +0,0 @@ -dn: inum=@!1111!2FDB.CF02,ou=scripts,o=gluu -objectClass: oxCustomScript -objectClass: top -description: Passport authentication module -displayName: passport -gluuStatus: false -inum: @!1111!2FDB.CF02 -oxConfigurationProperty: {"value1":"generic_remote_attributes_list","value2":"username, email, name, name, givenName, familyName, provider","description":""} -oxConfigurationProperty: {"value1":"generic_local_attributes_list","value2":"uid, mail, cn, displayName, givenName, sn, provider","description":""} -oxLevel: 60 -oxModuleProperty: {"value1":"usage_type","value2":"interactive","description":""} -oxModuleProperty: {"value1":"location_type","value2":"ldap","description":""} -oxRevision: 1 -oxScript:: -oxScriptType: person_authentication -programmingLanguage: python diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/phonefactor/pflogin.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/phonefactor/pflogin.xhtml deleted file mode 100644 index 75fb26f69c7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/phonefactor/pflogin.xhtml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - #{msgs['phonefactor.pageTitle']} - - -

- - - - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/postauthn/postauthn.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/postauthn/postauthn.py deleted file mode 100644 index 575acd35ccf..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/postauthn/postauthn.py +++ /dev/null @@ -1,53 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Zabrovarnyy -# -# -from __future__ import print_function - -from io.jans.model.custom.script.type.postauthn import PostAuthnType - -class PostAuthn(PostAuthnType): - - def __init__(self, currentTimeMillis): - """Construct class. - - Args: - currentTimeMillis (int): current time in miliseconds - """ - self.currentTimeMillis = currentTimeMillis - - @classmethod - def init(cls, customScript, configurationAttributes): - print("Post Authn script. Initializing ...") - print("Post Authn script. Initialized successfully") - - return True - - @classmethod - def destroy(cls, configurationAttributes): - print("Post Authn script. Destroying ...") - print("Post Authn script. Destroyed successfully") - return True - - @classmethod - def getApiVersion(cls): - return 11 - - # This method is called during Authorization Request at Authorization Endpoint. - # If True is returned, session is set as unauthenticated and user is send for authentication. - # Note : - # context is reference of io.jans.as.server.service.external.context.ExternalPostAuthnContext(in https://github.com/GluuFederation/oxauth project, ) - @classmethod - def forceReAuthentication(cls, context): - return False - - # This method is called during Authorization Request at Authorization Endpoint. - # If True is returned user is send for Authorization. By default if client is "Pre-Authorized" or "Client Persist Authorizations" is on, authorization is skipped. - # This script has higher priority and can cancel Pre-Authorization and persisted authorizations. - # Note : - # context is reference of io.jans.as.server.service.external.context.ExternalPostAuthnContext(in https://github.com/GluuFederation/oxauth project, ) - @classmethod - def forceAuthorization(cls, context): - return False diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/register.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/register.py deleted file mode 100644 index 3e1cce023ce..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/registration/register.py +++ /dev/null @@ -1,181 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.jsf2.message import FacesMessages -from jakarta.faces.application import FacesMessage -from io.jans.util import StringHelper, ArrayHelper -from java.util import Arrays, ArrayList, HashMap, IdentityHashMap -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import UserService, ClientService, AuthenticationService -from io.jans.util import StringHelper -from org.gluu.oxauth.model.common import User -from io.jans.as.server.util import ServerUtil -from io.jans.jsf2.service import FacesService -from org.gluu.oxauth.model.util import Base64Util -from org.python.core.util import StringUtil -from io.jans.as.server.service.net import HttpService -from jakarta.faces.context import FacesContext - -import java - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "Registration. Initialization" - print "Registration. Initialized successfully" - if (configurationAttributes.containsKey("generic_register_attributes_list") and - configurationAttributes.containsKey("generic_local_attributes_list")): - - remoteAttributesList = configurationAttributes.get("generic_register_attributes_list").getValue2() - if (StringHelper.isEmpty(remoteAttributesList)): - print "Registration: Initialization. The property generic_register_attributes_list is empty" - return False - - localAttributesList = configurationAttributes.get("generic_local_attributes_list").getValue2() - if (StringHelper.isEmpty(localAttributesList)): - print "Registration: Initialization. The property generic_local_attributes_list is empty" - return False - - self.attributesMapping = self.prepareAttributesMapping(remoteAttributesList, localAttributesList) - if (self.attributesMapping == None): - print "Registration: Initialization. The attributes mapping isn't valid" - return False - - return True - - - def destroy(self, configurationAttributes): - print "Registration. Destroy" - print "Registration. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - def getUserValueFromAuth(self, remote_attr, requestParameters): - try: - toBeFeatched = "loginForm:" + remote_attr - return ServerUtil.getFirstValue(requestParameters, toBeFeatched) - except Exception, err: - print("Registration: Exception inside getUserValueFromAuth " + str(err)) - - def authenticate(self, configurationAttributes, requestParameters, step): - print "Registration. Authenticate for step 1" - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - - if (StringHelper.isEmptyString(self.getUserValueFromAuth("email", requestParameters))): - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Please provide your email.") - return False - - if (StringHelper.isEmptyString(self.getUserValueFromAuth("pwd", requestParameters))): - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.add(FacesMessage.SEVERITY_ERROR, "Please provide password.") - return False - - - - foundUser = userService.getUserByAttribute("mail", self.getUserValueFromAuth("email", requestParameters)) - if (foundUser == None): - newUser = User() - for attributesMappingEntry in self.attributesMapping.entrySet(): - remoteAttribute = attributesMappingEntry.getKey() - localAttribute = attributesMappingEntry.getValue() - localAttributeValue = self.getUserValueFromAuth(remoteAttribute, requestParameters) - if ((localAttribute != None) & (localAttributeValue != "undefined")): - print localAttribute + localAttributeValue - newUser.setAttribute(localAttribute, localAttributeValue) - - try: - foundUser = userService.addUser(newUser, True) - foundUserName = foundUser.getUserId() - print("Registration: Found user name " + foundUserName) - userAuthenticated = authenticationService.authenticate(foundUserName) - print("Registration: User added successfully and isUserAuthenticated = " + str(userAuthenticated)) - except Exception, err: - print("Registration: Error in adding user:" + str(err)) - return False - return userAuthenticated - else: - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.add(FacesMessage.SEVERITY_ERROR, "User with same email already exists!") - return False - - - - def prepareForStep(self, configurationAttributes, requestParameters, step): - if (step == 1): - print "Registration. Prepare for Step 1" - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return None - - def getCountAuthenticationSteps(self, configurationAttributes): - return 1 - - def getPageForStep(self, configurationAttributes, step): - if step == 1: - return "/auth/register/register.xhtml" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def prepareAttributesMapping(self, remoteAttributesList, localAttributesList): - try: - remoteAttributesListArray = StringHelper.split(remoteAttributesList, ",") - if (ArrayHelper.isEmpty(remoteAttributesListArray)): - print("Registration: PrepareAttributesMapping. There is no attributes specified in remoteAttributesList property") - return None - - localAttributesListArray = StringHelper.split(localAttributesList, ",") - if (ArrayHelper.isEmpty(localAttributesListArray)): - print("Registration: PrepareAttributesMapping. There is no attributes specified in localAttributesList property") - return None - - if (len(remoteAttributesListArray) != len(localAttributesListArray)): - print("Registration: PrepareAttributesMapping. The number of attributes in remoteAttributesList and localAttributesList isn't equal") - return None - - attributeMapping = IdentityHashMap() - containsUid = False - i = 0 - count = len(remoteAttributesListArray) - while (i < count): - remoteAttribute = StringHelper.toLowerCase(remoteAttributesListArray[i]) - localAttribute = StringHelper.toLowerCase(localAttributesListArray[i]) - attributeMapping.put(remoteAttribute, localAttribute) - - i = i + 1 - - return attributeMapping - except Exception, err: - print("Registration: Exception inside prepareAttributesMapping " + str(err)) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml-passport/SamlPassportAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml-passport/SamlPassportAuthenticator.py deleted file mode 100644 index 7d823d55a4e..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml-passport/SamlPassportAuthenticator.py +++ /dev/null @@ -1,826 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Jose Gonzalez -# Author: Yuriy Movchan -# Author: Christian Eland -# - -from io.jans.jsf2.service import FacesService -from io.jans.jsf2.message import FacesMessages - -from org.gluu.oxauth.model.common import User, WebKeyStorage -from org.gluu.oxauth.model.configuration import AppConfiguration -from org.gluu.oxauth.model.crypto import CryptoProviderFactory -from org.gluu.oxauth.model.jwt import Jwt, JwtClaimName -from org.gluu.oxauth.model.util import Base64Util -from io.jans.as.server.service import AppInitializer, AuthenticationService -from io.jans.as.server.service.common import UserService, EncryptionService -from org.gluu.oxauth.model.authorize import AuthorizeRequestParam -from io.jans.as.server.service.net import HttpService -from io.jans.as.server.security import Identity -from io.jans.as.server.util import ServerUtil -from org.gluu.config.oxtrust import LdapOxPassportConfiguration -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.orm import PersistenceEntryManager -from io.jans.service.cdi.util import CdiUtil -from io.jans.util import StringHelper -from java.util import ArrayList, Arrays, Collections, HashSet -from org.gluu.oxauth.model.exception import InvalidJwtException -from jakarta.faces.application import FacesMessage -from jakarta.faces.context import FacesContext - -import json -import sys -import datetime -import base64 - - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - - print "Passport. init called" - - self.extensionModule = self.loadExternalModule(configurationAttributes.get("extension_module")) - extensionResult = self.extensionInit(configurationAttributes) - if extensionResult != None: - return extensionResult - - print "Passport. init. Behaviour is inbound SAML" - success = self.processKeyStoreProperties(configurationAttributes) - - if success: - self.providerKey = "provider" - self.customAuthzParameter = self.getCustomAuthzParameter(configurationAttributes.get("authz_req_param_provider")) - self.passportDN = self.getPassportConfigDN() - print "Passport. init. Initialization success" - else: - print "Passport. init. Initialization failed" - return success - - - def destroy(self, configurationAttributes): - print "Passport. destroy called" - return True - - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - - def authenticate(self, configurationAttributes, requestParameters, step): - - extensionResult = self.extensionAuthenticate(configurationAttributes, requestParameters, step) - if extensionResult != None: - return extensionResult - - print "Passport. authenticate for step %s called" % str(step) - identity = CdiUtil.bean(Identity) - - # Loading self.registeredProviders in case passport destroyed - if not hasattr(self,'registeredProviders'): - print "Passport. Fetching registered providers." - self.parseProviderConfigs() - - if step == 1: - - jwt_param = None - - if self.isInboundFlow(identity): - # if is idp-initiated inbound flow - print "Passport. authenticate for step 1. Detected idp-initiated inbound Saml flow" - # get request from session attributes - jwt_param = identity.getSessionId().getSessionAttributes().get(AuthorizeRequestParam.STATE) - print "jwt_param = %s" % jwt_param - # now jwt_param != None - - - - if jwt_param == None: - # gets jwt parameter "user" sent after authentication by passport (if exists) - jwt_param = ServerUtil.getFirstValue(requestParameters, "user") - - - if jwt_param != None: - # and now that the jwt_param user exists... - print "Passport. authenticate for step 1. JWT user profile token found" - - if self.isInboundFlow(identity): - jwt_param = base64.urlsafe_b64decode(str(jwt_param+'==')) - - # Parse JWT and validate - jwt = Jwt.parse(jwt_param) - - if not self.validSignature(jwt): - return False - - if self.jwtHasExpired(jwt): - return False - - # Gets user profile as string and json using the information on JWT - (user_profile, jsonp) = self.getUserProfile(jwt) - - if user_profile == None: - return False - - sessionAttributes = identity.getSessionId().getSessionAttributes() - self.skipProfileUpdate = StringHelper.equalsIgnoreCase(sessionAttributes.get("skipPassportProfileUpdate"), "true") - - return self.attemptAuthentication(identity, user_profile, jsonp) - - #See passportlogin.xhtml - provider = ServerUtil.getFirstValue(requestParameters, "loginForm:provider") - - if StringHelper.isEmpty(provider): - - #it's username + passw auth - print "Passport. authenticate for step 1. Basic authentication detected" - logged_in = False - - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - authenticationService = CdiUtil.bean(AuthenticationService) - logged_in = authenticationService.authenticate(user_name, user_password) - - print "Passport. authenticate for step 1. Basic authentication returned: %s" % logged_in - return logged_in - - - - elif provider in self.registeredProviders: - # user selected provider - # it's a recognized external IDP - - identity.setWorkingParameter("selectedProvider", provider) - print "Passport. authenticate for step 1. Retrying step 1" - - #see prepareForStep (step = 1) - return True - - if step == 2: - mail = ServerUtil.getFirstValue(requestParameters, "loginForm:email") - jsonp = identity.getWorkingParameter("passport_user_profile") - - if mail == None: - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email was missing in user profile") - elif jsonp != None: - # Completion of profile takes place - user_profile = json.loads(jsonp) - user_profile["mail"] = [ mail ] - - return self.attemptAuthentication(identity, user_profile, jsonp) - - print "Passport. authenticate for step 2. Failed: expected mail value in HTTP request and json profile in session" - return False - - - def prepareForStep(self, configurationAttributes, requestParameters, step): - - extensionResult = self.extensionPrepareForStep(configurationAttributes, requestParameters, step) - if extensionResult != None: - return extensionResult - - print "Passport. prepareForStep called %s" % str(step) - identity = CdiUtil.bean(Identity) - - if step == 1: - #re-read the strategies config (for instance to know which strategies have enabled the email account linking) - self.parseProviderConfigs() - identity.setWorkingParameter("externalProviders", json.dumps(self.registeredProviders)) - - providerParam = self.customAuthzParameter - url = None - - sessionAttributes = identity.getSessionId().getSessionAttributes() - self.skipProfileUpdate = StringHelper.equalsIgnoreCase(sessionAttributes.get("skipPassportProfileUpdate"), "true") - - #this param could have been set previously in authenticate step if current step is being retried - provider = identity.getWorkingParameter("selectedProvider") - print "prepareForStep %s - provider = %s" % (str(step), str(provider)) - - # if there is a selectedProvider - if provider != None: - - # get the redirect URL to use at facesService.redirectToExternalURL() that sends /passport/auth// - url = self.getPassportRedirectUrl(provider) - print "prepareForStep %s - url = %s" % (str(step), url) - - # sets selectedProvider back to None - identity.setWorkingParameter("selectedProvider", None) - - # if there is customAuthzParameter - elif providerParam != None: - - - # get it from sessionAtributes - paramValue = sessionAttributes.get(providerParam) - - #if exists - if paramValue != None: - print "Passport. prepareForStep. Found value in custom param of authorization request: %s" % paramValue - provider = self.getProviderFromJson(paramValue) - - if provider == None: - print "Passport. prepareForStep. A provider value could not be extracted from custom authorization request parameter" - elif not provider in self.registeredProviders: - print "Passport. prepareForStep. Provider '%s' not part of known configured IDPs/OPs" % provider - else: - url = self.getPassportRedirectUrl(provider) - - - # if no provider selected yet... - if url == None: - print "Passport. prepareForStep. A page to manually select an identity provider will be shown" - - # else already got the /passport/auth// url... - else: - - facesService = CdiUtil.bean(FacesService) - - # redirects to Passport getRedirectURL - sends browser to IDP. - print "Passport. Redirecting to external url: %s" + url - - facesService.redirectToExternalURL(url) - - return True - - - def getExtraParametersForStep(self, configurationAttributes, step): - print "Passport. getExtraParametersForStep called for step %s" % str(step) - if step == 1: - return Arrays.asList("selectedProvider", "externalProviders") - elif step == 2: - return Arrays.asList("passport_user_profile") - return None - - - def getCountAuthenticationSteps(self, configurationAttributes): - print "Passport. getCountAuthenticationSteps called" - identity = CdiUtil.bean(Identity) - if identity.getWorkingParameter("passport_user_profile") != None: - return 2 - return 1 - - - def getPageForStep(self, configurationAttributes, step): - print "Passport. getPageForStep called" - - extensionResult = self.extensionGetPageForStep(configurationAttributes, step) - if extensionResult != None: - return extensionResult - - if step == 1: - identity = CdiUtil.bean(Identity) - print "Passport. getPageForStep. Entered if step ==1" - if self.isInboundFlow(identity): - print "Passport. getPageForStep for step 1. Detected inbound Saml flow" - return "/postlogin.xhtml" - print "Passport. getPageForStep 1. NormalFlow, returning passportlogin.xhtml" - return "/auth/passport/passportlogin.xhtml" - - return "/auth/passport/passportpostlogin.xhtml" - - - def getNextStep(self, configurationAttributes, requestParameters, step): - if step == 1: - identity = CdiUtil.bean(Identity) - provider = identity.getWorkingParameter("selectedProvider") - if provider != None: - return 1 - - return -1 - - - def logout(self, configurationAttributes, requestParameters): - return True - -# Extension module related functions - - def extensionInit(self, configurationAttributes): - - if self.extensionModule == None: - return None - return self.extensionModule.init(configurationAttributes) - - - def extensionAuthenticate(self, configurationAttributes, requestParameters, step): - - if self.extensionModule == None: - return None - return self.extensionModule.authenticate(configurationAttributes, requestParameters, step) - - - def extensionPrepareForStep(self, configurationAttributes, requestParameters, step): - - if self.extensionModule == None: - return None - return self.extensionModule.prepareForStep(configurationAttributes, requestParameters, step) - - - def extensionGetPageForStep(self, configurationAttributes, step): - - if self.extensionModule == None: - return None - return self.extensionModule.getPageForStep(configurationAttributes, step) - -# Initalization routines - - def loadExternalModule(self, simpleCustProperty): - - if simpleCustProperty != None: - print "Passport. loadExternalModule. Loading passport extension module..." - moduleName = simpleCustProperty.getValue2() - try: - module = __import__(moduleName) - return module - except: - print "Passport. loadExternalModule. Failed to load module %s" % moduleName - print "Exception: ", sys.exc_info()[1] - print "Passport. loadExternalModule. Flow will be driven entirely by routines of main passport script" - return None - - - def processKeyStoreProperties(self, attrs): - file = attrs.get("key_store_file") - password = attrs.get("key_store_password") - - if file != None and password != None: - file = file.getValue2() - password = password.getValue2() - - if StringHelper.isNotEmpty(file) and StringHelper.isNotEmpty(password): - self.keyStoreFile = file - self.keyStorePassword = password - return True - - print "Passport. readKeyStoreProperties. Properties key_store_file or key_store_password not found or empty" - return False - - - def getCustomAuthzParameter(self, simpleCustProperty): - - customAuthzParameter = None - if simpleCustProperty != None: - prop = simpleCustProperty.getValue2() - if StringHelper.isNotEmpty(prop): - customAuthzParameter = prop - - if customAuthzParameter == None: - print "Passport. getCustomAuthzParameter. No custom param for OIDC authz request in script properties" - print "Passport. getCustomAuthzParameter. Passport flow cannot be initiated by doing an OpenID connect authorization request" - else: - print "Passport. getCustomAuthzParameter. Custom param for OIDC authz request in script properties: %s" % customAuthzParameter - - return customAuthzParameter - -# Configuration parsing - - def getPassportConfigDN(self): - - f = open('/etc/gluu/conf/gluu.properties', 'r') - for line in f: - prop = line.split("=") - if prop[0] == "oxpassport_ConfigurationEntryDN": - prop.pop(0) - break - - f.close() - return "=".join(prop).strip() - - - def parseAllProviders(self): - - registeredProviders = {} - print "Passport. parseAllProviders. Adding providers" - entryManager = CdiUtil.bean(PersistenceEntryManager) - - config = LdapOxPassportConfiguration() - config = entryManager.find(config.getClass(), self.passportDN).getPassportConfiguration() - config = config.getProviders() if config != None else config - - if config != None and len(config) > 0: - for prvdetails in config: - if prvdetails.isEnabled(): - registeredProviders[prvdetails.getId()] = { - "emailLinkingSafe": prvdetails.isEmailLinkingSafe(), - "requestForEmail" : prvdetails.isRequestForEmail(), - "logo_img": prvdetails.getLogoImg(), - "displayName": prvdetails.getDisplayName(), - "type": prvdetails.getType() - } - - return registeredProviders - - - def parseProviderConfigs(self): - - registeredProviders = {} - try: - registeredProviders = self.parseAllProviders() - toRemove = [] - - for provider in registeredProviders: - if registeredProviders[provider]["type"] != "saml": - toRemove.append(provider) - else: - registeredProviders[provider]["saml"] = True - - for provider in toRemove: - registeredProviders.pop(provider) - - - if len(registeredProviders.keys()) > 0: - print "Passport. parseProviderConfigs. Configured providers:", registeredProviders - else: - print "Passport. parseProviderConfigs. No providers registered yet" - except: - print "Passport. parseProviderConfigs. An error occurred while building the list of supported authentication providers", sys.exc_info()[1] - - - print "parseProviderConfigs - registeredProviders = %s" % str(registeredProviders) - self.registeredProviders = registeredProviders - print "parseProviderConfigs - self.registeredProviders = %s" % str(self.registeredProviders) - -# Auxiliary routines - - def getProviderFromJson(self, providerJson): - - provider = None - try: - obj = json.loads(Base64Util.base64urldecodeToString(providerJson)) - provider = obj[self.providerKey] - except: - print "Passport. getProviderFromJson. Could not parse provided Json string. Returning None" - - return provider - - - def getPassportRedirectUrl(self, provider): - - # provider is assumed to exist in self.registeredProviders - url = None - try: - facesContext = CdiUtil.bean(FacesContext) - tokenEndpoint = "https://%s/passport/token" % facesContext.getExternalContext().getRequest().getServerName() - - httpService = CdiUtil.bean(HttpService) - httpclient = httpService.getHttpsClient() - - print "Passport. getPassportRedirectUrl. Obtaining token from passport at %s" % tokenEndpoint - resultResponse = httpService.executeGet(httpclient, tokenEndpoint, Collections.singletonMap("Accept", "text/json")) - httpResponse = resultResponse.getHttpResponse() - - bytes = httpService.getResponseContent(httpResponse) - - response = httpService.convertEntityToString(bytes) - print "Passport. getPassportRedirectUrl. Response was %s" % httpResponse.getStatusLine().getStatusCode() - - tokenObj = json.loads(response) - - url = "/passport/auth/%s/%s" % (provider, tokenObj["token_"]) - - except: - print "Passport. getPassportRedirectUrl. Error building redirect URL: ", sys.exc_info()[1] - - return url - - - def validSignature(self, jwt): - - print "Passport. validSignature. Checking JWT token signature" - valid = False - - try: - - appConfiguration = AppConfiguration() - appConfiguration.setWebKeysStorage(WebKeyStorage.KEYSTORE) - appConfiguration.setKeyStoreFile(self.keyStoreFile) - appConfiguration.setKeyStoreSecret(self.keyStorePassword) - appConfiguration.setKeyRegenerationEnabled(False) - - cryptoProvider = CryptoProviderFactory.getCryptoProvider(appConfiguration) - - - alg_string = str(jwt.getHeader().getSignatureAlgorithm()) - signature_string = str(jwt.getEncodedSignature()) - - if alg_string == "none" or alg_string == "None" or alg_string == "NoNe" or alg_string == "nONE" or alg_string == "NONE" or alg_string == "NonE" or alg_string == "nOnE": - # blocks none attack - - print "WARNING: JWT Signature algorithm is none" - valid = False - - elif alg_string != "RS512": - # blocks anything that's not RS512 - - print "WARNING: JWT Signature algorithm is NOT RS512" - valid = False - - elif signature_string == "" : - # blocks empty signature string - print "WARNING: JWT Signature not sent" - valid = False - - else: - - # class extends AbstractCryptoProvider - ''' on version 4.2 .getAlgorithm() method was renamed to .getSignatureAlgorithm() - for older versions: - valid = cryptoProvider.verifySignature(jwt.getSigningInput(), jwt.getEncodedSignature(), jwt.getHeader().getKeyId(), - None, None, jwt.getHeader().getAlgorithm()) - ''' - - # working on 4.2: - valid = cryptoProvider.verifySignature(jwt.getSigningInput(), jwt.getEncodedSignature(), jwt.getHeader().getKeyId(), - None, None, jwt.getHeader().getSignatureAlgorithm()) - - except: - print "Exception: ", sys.exc_info()[1] - - print "Passport. validSignature. Validation result was %s" % valid - - return valid - - - def jwtHasExpired(self, jwt): - # Check if jwt has expired - jwt_claims = jwt.getClaims() - try: - exp_date_timestamp = float(jwt_claims.getClaimAsString(JwtClaimName.EXPIRATION_TIME)) - exp_date = datetime.datetime.fromtimestamp(exp_date_timestamp) - hasExpired = exp_date < datetime.datetime.now() - except: - print "Exception: The JWT does not have '%s' attribute" % JwtClaimName.EXPIRATION_TIME - return False - - return hasExpired - - - def getUserProfile(self, jwt): - - # getClaims method located at org.gluu.oxauth.model.token.JsonWebResponse.java as a org.gluu.oxauth.model.jwt.JwtClaims object - jwt_claims = jwt.getClaims() - - user_profile_json = None - - try: - # public String getClaimAsString(String key) - user_profile_json = CdiUtil.bean(EncryptionService).decrypt(jwt_claims.getClaimAsString("data")) - - user_profile = json.loads(user_profile_json) - except: - print "Passport. getUserProfile. Problem obtaining user profile json representation" - - return (user_profile, user_profile_json) - - - def attemptAuthentication(self, identity, user_profile, user_profile_json): - - print "Entered attemptAuthentication..." - uidKey = "uid" - if not self.checkRequiredAttributes(user_profile, [uidKey, self.providerKey]): - return False - - provider = user_profile[self.providerKey] - print "user_profile[self.providerKey] = %s" % str(user_profile[self.providerKey]) - if not provider in self.registeredProviders: - print "Entered if note provider in self.registeredProviers:" - print "Passport. attemptAuthentication. Identity Provider %s not recognized" % provider - return False - - print "attemptAuthentication. user_profile = %s" % user_profile - print "user_profile[uidKey] = %s" % user_profile[uidKey] - uid = user_profile[uidKey][0] - print "attemptAuthentication - uid = %s" % uid - externalUid = "passport-%s:%s:%s" % ("saml", provider, uid) - - userService = CdiUtil.bean(UserService) - userByUid = self.getUserByExternalUid(uid, provider, userService) - - email = None - if "mail" in user_profile: - email = user_profile["mail"] - if len(email) == 0: - email = None - else: - email = email[0] - user_profile["mail"] = [ email ] - - if email == None and self.registeredProviders[provider]["requestForEmail"]: - print "Passport. attemptAuthentication. Email was not received" - - if userByUid != None: - # This avoids asking for the email over every login attempt - email = userByUid.getAttribute("mail") - if email != None: - print "Passport. attemptAuthentication. Filling missing email value with %s" % email - user_profile["mail"] = [ email ] - - if email == None: - # Store user profile in session and abort this routine - identity.setWorkingParameter("passport_user_profile", user_profile_json) - return True - - userByMail = None if email == None else userService.getUserByAttribute("mail", email) - - # Determine if we should add entry, update existing, or deny access - doUpdate = False - doAdd = False - if userByUid != None: - print "User with externalUid '%s' already exists" % externalUid - if userByMail == None: - doUpdate = True - else: - if userByMail.getUserId() == userByUid.getUserId(): - doUpdate = True - else: - print "Users with externalUid '%s' and mail '%s' are different. Access will be denied. Impersonation attempt?" % (externalUid, email) - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email value corresponds to an already existing provisioned account") - else: - if userByMail == None: - doAdd = True - elif self.registeredProviders[provider]["emailLinkingSafe"]: - - tmpList = userByMail.getAttributeValues("oxExternalUid") - tmpList = ArrayList() if tmpList == None else ArrayList(tmpList) - tmpList.add(externalUid) - userByMail.setAttribute("oxExternalUid", tmpList, True) - - userByUid = userByMail - print "External user supplying mail %s will be linked to existing account '%s'" % (email, userByMail.getUserId()) - doUpdate = True - else: - print "An attempt to supply an email of an existing user was made. Turn on 'emailLinkingSafe' if you want to enable linking" - self.setMessageError(FacesMessage.SEVERITY_ERROR, "Email value corresponds to an already existing account. If you already have a username and password use those instead of an external authentication site to get access.") - - username = None - try: - if doUpdate: - username = userByUid.getUserId() - print "Passport. attemptAuthentication. Updating user %s" % username - self.updateUser(userByUid, user_profile, userService) - elif doAdd: - print "Passport. attemptAuthentication. Creating user %s" % externalUid - newUser = self.addUser(externalUid, user_profile, userService) - username = newUser.getUserId() - except: - print "Exception: ", sys.exc_info()[1] - print "Passport. attemptAuthentication. Authentication failed" - return False - - if username == None: - print "Passport. attemptAuthentication. Authentication attempt was rejected" - return False - else: - logged_in = CdiUtil.bean(AuthenticationService).authenticate(username) - print "Passport. attemptAuthentication. Authentication for %s returned %s" % (username, logged_in) - return logged_in - - - def getUserByExternalUid(self, uid, provider, userService): - newFormat = "passport-%s:%s:%s" % ("saml", provider, uid) - user = userService.getUserByAttribute("oxExternalUid", newFormat, True) - - if user == None: - oldFormat = "passport-%s:%s" % ("saml", uid) - user = userService.getUserByAttribute("oxExternalUid", oldFormat, True) - - if user != None: - # Migrate to newer format - list = HashSet(user.getAttributeValues("oxExternalUid")) - list.remove(oldFormat) - list.add(newFormat) - user.setAttribute("oxExternalUid", ArrayList(list), True) - print "Migrating user's oxExternalUid to newer format 'passport-saml:provider:uid'" - userService.updateUser(user) - - return user - - - def setMessageError(self, severity, msg): - facesMessages = CdiUtil.bean(FacesMessages) - facesMessages.setKeepMessages() - facesMessages.clear() - facesMessages.add(severity, msg) - - - def checkRequiredAttributes(self, profile, attrs): - - for attr in attrs: - if (not attr in profile) or len(profile[attr]) == 0: - print "Passport. checkRequiredAttributes. Attribute '%s' is missing in profile" % attr - return False - return True - - - def addUser(self, externalUid, profile, userService): - print "Passport. Entered addUser()." - print "Passport. addUser. externalUid = %s" % externalUid - print "Passport. addUser. profile = %s" % profile - newUser = User() - #Fill user attrs - newUser.setAttribute("oxExternalUid", externalUid, True) - self.fillUser(newUser, profile) - newUser = userService.addUser(newUser, True) - return newUser - - - def updateUser(self, foundUser, profile, userService): - # when this is false, there might still some updates taking place (e.g. not related to profile attrs released by external provider) - if (not self.skipProfileUpdate): - self.fillUser(foundUser, profile) - userService.updateUser(foundUser) - - - def fillUser(self, foundUser, profile): - print - print "Passport. Entered fillUser()." - print "Passport. fillUser. foundUser = %s" % foundUser - print "Passport. fillUser. profile = %s" % profile - for attr in profile: - # "provider" is disregarded if part of mapping - if attr != self.providerKey: - values = profile[attr] - print "%s = %s" % (attr, values) - foundUser.setAttribute(attr, values) - - if attr == "mail": - print "Passport. fillUser. entered if attr == mail" - oxtrustMails = [] - for mail in values: - oxtrustMails.append('{"value":"%s","primary":false}' % mail) - foundUser.setAttribute("oxTrustEmail", oxtrustMails) - -# IDP-initiated flow routines - - def isInboundFlow(self, identity): - print "passport. entered isInboundFlow" - - sessionId = identity.getSessionId() - print "passport. isInboundFlow. sessionId = %s" % sessionId - if sessionId == None: - print "passport. isInboundFlow. sessionId not found yet..." - # Detect mode if there is no session yet. It's needed for getPageForStep method - facesContext = CdiUtil.bean(FacesContext) - requestParameters = facesContext.getExternalContext().getRequestParameterMap() - print "passport. isInboundFlow. requestParameters = %s" % requestParameters - - authz_state = requestParameters.get(AuthorizeRequestParam.STATE) - print "passport. isInboundFlow. authz_state = %s" % authz_state - else: - authz_state = identity.getSessionId().getSessionAttributes().get(AuthorizeRequestParam.STATE) - - print "passport. IsInboundFlow. authz_state = %s" % authz_state - - # the replace above is workaround due a problem reported - # on issue: https://github.com/GluuFederation/gluu-passport/issues/95 - # TODO: Remove after fixed on JSF side - - b64url_decoded_auth_state = base64.urlsafe_b64decode(str(authz_state+'==')) - - # print "passport. IsInboundFlow. b64url_decoded_auth_state = %s" % str(b64url_decoded_auth_state) - print "passport. IsInboundFlow. self.isInboundJwt() = %s" % str(self.isInboundJwt(b64url_decoded_auth_state)) - if self.isInboundJwt(b64url_decoded_auth_state): - return True - - return False - - - def isInboundJwt(self, value): - if value == None: - return False - - try: - jwt = Jwt.parse(value) - print "passport.isInboundJwt. jwt = %s" % jwt - user_profile_json = CdiUtil.bean(EncryptionService).decrypt(jwt.getClaims().getClaimAsString("data")) - if StringHelper.isEmpty(user_profile_json): - return False - except InvalidJwtException: - return False - - except: - print("Unexpected error:", sys.exc_info()[0]) - return False - - return True - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/Gluu Inbound SAML Design (no Session).png b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/saml/Gluu Inbound SAML Design (no Session).png deleted file mode 100644 index 14f67ddf1725a658243e5a7830d99e8148909974..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52535 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 0): - userToSearch.setAttribute(userAttributeName, attribute_values_list) - - users = userService.getUsersBySample(userToSearch, 1) - if users.size() > 0: - return False - - return True - - def getMappedUser(self, configurationAttributes, requestParameters, saml_response_attributes): - # Convert Saml result attributes keys to lover case - saml_response_normalized_attributes = HashMap() - for saml_response_attribute_entry in saml_response_attributes.entrySet(): - saml_response_normalized_attributes.put(StringHelper.toLowerCase(saml_response_attribute_entry.getKey()), saml_response_attribute_entry.getValue()) - - currentAttributesMapping = self.prepareCurrentAttributesMapping(self.attributesMapping, configurationAttributes, requestParameters) - print "Asimba. Get mapped user. Using next attributes mapping '%s'" % currentAttributesMapping - - newUser = User() - - # Set custom object classes - if self.userObjectClasses != None: - print "Asimba. Get mapped user. User custom objectClasses to add persons: '%s'" % Util.array2ArrayList(self.userObjectClasses) - newUser.setCustomObjectClasses(self.userObjectClasses) - - for attributesMappingEntry in currentAttributesMapping.entrySet(): - idpAttribute = attributesMappingEntry.getKey() - localAttribute = attributesMappingEntry.getValue() - - if self.debugEnrollment: - print "Asimba. Get mapped user. Trying to map '%s' into '%s'" % (idpAttribute, localAttribute) - - localAttributeValue = saml_response_normalized_attributes.get(idpAttribute) - if localAttributeValue != None: - if self.debugEnrollment: - print "Asimba. Get mapped user. Setting attribute '%s' value '%s'" % (localAttribute, localAttributeValue) - newUser.setAttribute(localAttribute, localAttributeValue) - else: - if newUser.getAttribute(localAttribute) == None: - newUser.setAttribute(localAttribute, ArrayList()) - - return newUser - - def getMappedAllAttributesUser(self, saml_response_attributes): - user = User() - - # Set custom object classes - if self.userObjectClasses != None: - print "Asimba. Get mapped all attributes user. User custom objectClasses to add persons: '%s'" % Util.array2ArrayList(self.userObjectClasses) - user.setCustomObjectClasses(self.userObjectClasses) - - # Prepare map to do quick mapping - attributeService = CdiUtil.bean(AttributeService) - ldapAttributes = attributeService.getAllAttributes() - samlUriToAttributesMap = HashMap() - for ldapAttribute in ldapAttributes: - saml2Uri = ldapAttribute.getSaml2Uri() - if saml2Uri == None: - saml2Uri = attributeService.getDefaultSaml2Uri(ldapAttribute.getName()) - samlUriToAttributesMap.put(saml2Uri, ldapAttribute.getName()) - - customAttributes = ArrayList() - for key in saml_response_attributes.keySet(): - ldapAttributeName = samlUriToAttributesMap.get(key) - if ldapAttributeName == None: - print "Asimba. Get mapped all attributes user. Skipping saml attribute: '%s'" % key - continue - - if StringHelper.equalsIgnoreCase(ldapAttributeName, "uid"): - continue - - attribute = CustomAttribute(ldapAttributeName) - attribute.setValues(saml_response_attributes.get(key)) - customAttributes.add(attribute) - - user.setCustomAttributes(customAttributes) - - return user - - def getNameId(self, samlResponse, newUser): - if self.generateNameId: - saml_user_uid = self.generateNameUid(newUser) - else: - saml_user_uid = self.getSamlNameId(samlResponse) - - return saml_user_uid - - def getSamlNameId(self, samlResponse): - saml_response_name_id = samlResponse.getNameId() - if StringHelper.isEmpty(saml_response_name_id): - print "Asimba. Get Saml response. saml_response_name_id is invalid" - return None - - print "Asimba. Get Saml response. saml_response_name_id: '%s'" % saml_response_name_id - - # Use persistent Id as saml_user_uid - return saml_response_name_id - - def generateNameUid(self, user): - if self.userEnforceAttributesUniqueness == None: - print "Asimba. Build local external uid. User enforce attributes uniqueness not specified" - return None - - sb = StringBuilder() - first = True - for userAttributeName in self.userEnforceAttributesUniqueness: - if not first: - sb.append("!") - first = False - attribute_values_list = user.getAttributeValues(userAttributeName) - if (attribute_values_list != None) and (attribute_values_list.size() > 0): - first_attribute_value = attribute_values_list.get(0) - sb.append(first_attribute_value) - - return sb.toString() - - def setDefaultUid(self, user, saml_user_uid): - if StringHelper.isEmpty(user.getUserId()): - user.setUserId(saml_user_uid) diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.jar b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.jar deleted file mode 100644 index 0af9d618a8ee7bbf1341e46e944e6f74e03a25d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28229 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 sLir>5&z=%*(esV}k4gVPzkOy@2Hd| - - 4.0.0 - com.google.gcm - gcm-server - 1.0.1.gluu - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.md5 b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.md5 deleted file mode 100644 index 6126b5f4080..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.md5 +++ /dev/null @@ -1 +0,0 @@ -3e2f5fe7273ec568da5d8daab6cb99a3 \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.sha1 b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.sha1 deleted file mode 100644 index eb0541fd960..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/1.0.1.gluu/gcm-server-1.0.1.gluu.pom.sha1 +++ /dev/null @@ -1 +0,0 @@ -82419a7d510b6809d6e34dcf84b12fccd3d63ab1 \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml deleted file mode 100644 index 3fe315a7a2a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - com.google.gcm - gcm-server - - 1.0.1.gluu - - 1.0.1.gluu - - 20160713194346 - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.md5 b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.md5 deleted file mode 100644 index bd2630a92ec..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.md5 +++ /dev/null @@ -1 +0,0 @@ -6ed9b8a162275e13f176b718271fabac \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.sha1 b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.sha1 deleted file mode 100644 index 4083cf36c54..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/repository/com/google/gcm/gcm-server/maven-metadata.xml.sha1 +++ /dev/null @@ -1 +0,0 @@ -2c9a252aa4d788e7702cac5dafb31e0dd6393acf \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/sample/super_gluu_creds.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/sample/super_gluu_creds.json deleted file mode 100644 index b42f5a6b5ef..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/super_gluu/sample/super_gluu_creds.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "android":{ - "gcm":{ - "enabled":false, - "api_key":"" - }, - "sns":{ - "enabled":false, - "platform_arn":"arn:aws:sns:..." - }, - "gluu":{ - "enabled":true, - "access_key":"36WH2JiexBOoAIBP", - "secret_access_key":"ueqsU2Dc7m3r4HmLz4M79DpzzCNqTfek" - } - }, - "ios":{ - "apns":{ - "enabled":false, - "p12_file_path":"/etc/certs/SuperGluu-NotificationCertificate.p12", - "p12_password":"password", - "production":false - }, - "sns":{ - "enabled":false, - "platform_arn":"arn:aws:sns:...", - "production":false - }, - "gluu":{ - "enabled":true, - "access_key":"auONAdePWoYFBX6V", - "secret_access_key":"f050aW0nnihym0GwktWd7O15jGSQcoei" - } - }, - "sns":{ - "access_key":"", - "secret_key":"", - "region":"" - }, - "gluu":{ - "server_uri":"https://api.gluu.org" - } -} diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tpauthenticate.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tpauthenticate.xhtml deleted file mode 100644 index 2b97893b950..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tpauthenticate.xhtml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - #{msgs['toopher.pageTitle']} - - -

- - - - - - \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tppair.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tppair.xhtml deleted file mode 100644 index a28ce1a08be..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/toopher/tppair.xhtml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - oxAuth Toopher - Login - - -
- - - -
-
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/UafExternalAuthenticator.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/UafExternalAuthenticator.py deleted file mode 100644 index 7fcb634d9a1..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/UafExternalAuthenticator.py +++ /dev/null @@ -1,398 +0,0 @@ -# Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. -# Copyright (c) 2020, Janssen Project -# -# Author: Yuriy Movchan -# - -# Requires the following custom properties and values: -# uaf_server_uri: -# -# These are non mandatory custom properties and values: -# uaf_policy_name: default -# send_push_notifaction: false -# registration_uri: https:///identity/register -# qr_options: { width: 400, height: 400 } - -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from io.jans.as.server.service import AuthenticationService, SessionIdService -from io.jans.as.server.service.common import UserService -from io.jans.util import StringHelper, ArrayHelper -from io.jans.as.server.util import ServerUtil -from org.gluu.oxauth.model.config import Constants -from jakarta.ws.rs.core import Response -from java.util import Arrays -from io.jans.as.server.service.net import HttpService -from org.apache.http.params import CoreConnectionPNames - -import sys -import java -import json - -class PersonAuthentication(PersonAuthenticationType): - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - - def init(self, customScript, configurationAttributes): - print "UAF. Initialization" - - if not configurationAttributes.containsKey("uaf_server_uri"): - print "UAF. Initialization. Property uaf_server_uri is mandatory" - return False - - self.uaf_server_uri = configurationAttributes.get("uaf_server_uri").getValue2() - - self.uaf_policy_name = "default" - if configurationAttributes.containsKey("uaf_policy_name"): - self.uaf_policy_name = configurationAttributes.get("uaf_policy_name").getValue2() - - self.send_push_notifaction = False - if configurationAttributes.containsKey("send_push_notifaction"): - self.send_push_notifaction = StringHelper.toBoolean(configurationAttributes.get("send_push_notifaction").getValue2(), False) - - self.registration_uri = None - if configurationAttributes.containsKey("registration_uri"): - self.registration_uri = configurationAttributes.get("registration_uri").getValue2() - - self.customQrOptions = {} - if configurationAttributes.containsKey("qr_options"): - self.customQrOptions = configurationAttributes.get("qr_options").getValue2() - - print "UAF. Initializing HTTP client" - httpService = CdiUtil.bean(HttpService) - self.http_client = httpService.getHttpsClient() - http_client_params = self.http_client.getParams() - http_client_params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15 * 1000) - - print "UAF. Initialized successfully. uaf_server_uri: '%s', uaf_policy_name: '%s', send_push_notifaction: '%s', registration_uri: '%s', qr_options: '%s'" % (self.uaf_server_uri, self.uaf_policy_name, self.send_push_notifaction, self.registration_uri, self.customQrOptions) - - print "UAF. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "UAF. Destroy" - print "UAF. Destroyed successfully" - return True - - def getApiVersion(self): - return 11 - - def getAuthenticationMethodClaims(self, requestParameters): - return None - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def authenticate(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - session_attributes = identity.getSessionId().getSessionAttributes() - - self.setRequestScopedParameters(identity) - - if (step == 1): - print "UAF. Authenticate for step 1" - - user_name = credentials.getUsername() - - authenticated_user = self.processBasicAuthentication(credentials) - if authenticated_user == None: - return False - - uaf_auth_method = "authenticate" - # Uncomment this block if you need to allow user second device registration - #enrollment_mode = ServerUtil.getFirstValue(requestParameters, "loginForm:registerButton") - #if StringHelper.isNotEmpty(enrollment_mode): - # uaf_auth_method = "enroll" - - if uaf_auth_method == "authenticate": - user_enrollments = self.findEnrollments(credentials) - if len(user_enrollments) == 0: - uaf_auth_method = "enroll" - print "UAF. Authenticate for step 1. There is no UAF enrollment for user '%s'. Changing uaf_auth_method to '%s'" % (user_name, uaf_auth_method) - - print "UAF. Authenticate for step 1. uaf_auth_method: '%s'" % uaf_auth_method - - identity.setWorkingParameter("uaf_auth_method", uaf_auth_method) - - return True - elif (step == 2): - print "UAF. Authenticate for step 2" - - session = CdiUtil.bean(SessionIdService).getSessionId() - if session == None: - print "UAF. Prepare for step 2. Failed to determine session_id" - return False - - user = authenticationService.getAuthenticatedUser() - if (user == None): - print "UAF. Authenticate for step 2. Failed to determine user name" - return False - user_name = user.getUserId() - - uaf_auth_result = ServerUtil.getFirstValue(requestParameters, "auth_result") - if uaf_auth_result != "success": - print "UAF. Authenticate for step 2. auth_result is '%s'" % uaf_auth_result - return False - - # Restore state from session - uaf_auth_method = session_attributes.get("uaf_auth_method") - - if not uaf_auth_method in ['enroll', 'authenticate']: - print "UAF. Authenticate for step 2. Failed to authenticate user. uaf_auth_method: '%s'" % uaf_auth_method - return False - - # Request STATUS_OBB - if True: - #TODO: Remove this condition - # It's workaround becuase it's not possible to call STATUS_OBB 2 times. First time on browser and second ime on server - uaf_user_device_handle = ServerUtil.getFirstValue(requestParameters, "auth_handle") - else: - uaf_obb_auth_method = session_attributes.get("uaf_obb_auth_method") - uaf_obb_server_uri = session_attributes.get("uaf_obb_server_uri") - uaf_obb_start_response = session_attributes.get("uaf_obb_start_response") - - # Prepare STATUS_OBB - uaf_obb_start_response_json = json.loads(uaf_obb_start_response) - uaf_obb_status_request_dictionary = { "operation": "STATUS_%s" % uaf_obb_auth_method, - "userName": user_name, - "needDetails": 1, - "oobStatusHandle": uaf_obb_start_response_json["oobStatusHandle"], - } - - uaf_obb_status_request = json.dumps(uaf_obb_status_request_dictionary, separators=(',',':')) - print "UAF. Authenticate for step 2. Prepared STATUS request: '%s' to send to '%s'" % (uaf_obb_status_request, uaf_obb_server_uri) - - uaf_status_obb_response = self.executePost(uaf_obb_server_uri, uaf_obb_status_request) - if uaf_status_obb_response == None: - return False - - print "UAF. Authenticate for step 2. Get STATUS response: '%s'" % uaf_status_obb_response - uaf_status_obb_response_json = json.loads(uaf_status_obb_response) - - if uaf_status_obb_response_json["statusCode"] != 4000: - print "UAF. Authenticate for step 2. UAF operation status is invalid. statusCode: '%s'" % uaf_status_obb_response_json["statusCode"] - return False - - uaf_user_device_handle = uaf_status_obb_response_json["additionalInfo"]["authenticatorsResult"]["handle"] - - if StringHelper.isEmpty(uaf_user_device_handle): - print "UAF. Prepare for step 2. Failed to get UAF handle" - return False - - uaf_user_external_uid = "uaf:%s" % uaf_user_device_handle - print "UAF. Authenticate for step 2. UAF handle: '%s'" % uaf_user_external_uid - - if uaf_auth_method == "authenticate": - # Validate if user used device with same keYHandle - user_enrollments = self.findEnrollments(credentials) - if len(user_enrollments) == 0: - uaf_auth_method = "enroll" - print "UAF. Authenticate for step 2. There is no UAF enrollment for user '%s'." % user_name - return False - - for user_enrollment in user_enrollments: - if StringHelper.equalsIgnoreCase(user_enrollment, uaf_user_device_handle): - print "UAF. Authenticate for step 2. There is UAF enrollment for user '%s'. User authenticated successfully" % user_name - return True - else: - userService = CdiUtil.bean(UserService) - - # Double check just to make sure. We did checking in previous step - # Check if there is user which has uaf_user_external_uid - # Avoid mapping user cert to more than one IDP account - find_user_by_external_uid = userService.getUserByAttribute("oxExternalUid", uaf_user_external_uid) - if find_user_by_external_uid == None: - # Add uaf_user_external_uid to user's external GUID list - find_user_by_external_uid = userService.addUserAttribute(user_name, "oxExternalUid", uaf_user_external_uid) - if find_user_by_external_uid == None: - print "UAF. Authenticate for step 2. Failed to update current user" - return False - - return True - - return False - else: - return False - - def prepareForStep(self, configurationAttributes, requestParameters, step): - authenticationService = CdiUtil.bean(AuthenticationService) - - identity = CdiUtil.bean(Identity) - credentials = identity.getCredentials() - - session_attributes = identity.getSessionId().getSessionAttributes() - - self.setRequestScopedParameters(identity) - - if (step == 1): - return True - elif (step == 2): - print "UAF. Prepare for step 2" - - session = CdiUtil.bean(SessionIdService).getSessionId() - if session == None: - print "UAF. Prepare for step 2. Failed to determine session_id" - return False - - user = authenticationService.getAuthenticatedUser() - if (user == None): - print "UAF. Prepare for step 2. Failed to determine user name" - return False - - uaf_auth_method = session_attributes.get("uaf_auth_method") - if StringHelper.isEmpty(uaf_auth_method): - print "UAF. Prepare for step 2. Failed to determine auth_method" - return False - - print "UAF. Prepare for step 2. uaf_auth_method: '%s'" % uaf_auth_method - - uaf_obb_auth_method = "OOB_REG" - uaf_obb_server_uri = self.uaf_server_uri + "/nnl/v2/reg" - if StringHelper.equalsIgnoreCase(uaf_auth_method, "authenticate"): - uaf_obb_auth_method = "OOB_AUTH" - uaf_obb_server_uri = self.uaf_server_uri + "/nnl/v2/auth" - - # Prepare START_OBB - uaf_obb_start_request_dictionary = { "operation": "START_%s" % uaf_obb_auth_method, - "userName": user.getUserId(), - "policyName": "default", - "oobMode": - { "qr": "true", "rawData": "false", "push": "false" } - } - - uaf_obb_start_request = json.dumps(uaf_obb_start_request_dictionary, separators=(',',':')) - print "UAF. Prepare for step 2. Prepared START request: '%s' to send to '%s'" % (uaf_obb_start_request, uaf_obb_server_uri) - - # Request START_OBB - uaf_obb_start_response = self.executePost(uaf_obb_server_uri, uaf_obb_start_request) - if uaf_obb_start_response == None: - return False - - print "UAF. Prepare for step 2. Get START response: '%s'" % uaf_obb_start_response - uaf_obb_start_response_json = json.loads(uaf_obb_start_response) - - # Prepare STATUS_OBB - #TODO: Remove needDetails parameter - uaf_obb_status_request_dictionary = { "operation": "STATUS_%s" % uaf_obb_auth_method, - "userName": user.getUserId(), - "needDetails": 1, - "oobStatusHandle": uaf_obb_start_response_json["oobStatusHandle"], - } - - uaf_obb_status_request = json.dumps(uaf_obb_status_request_dictionary, separators=(',',':')) - print "UAF. Prepare for step 2. Prepared STATUS request: '%s' to send to '%s'" % (uaf_obb_status_request, uaf_obb_server_uri) - - identity.setWorkingParameter("uaf_obb_auth_method", uaf_obb_auth_method) - identity.setWorkingParameter("uaf_obb_server_uri", uaf_obb_server_uri) - identity.setWorkingParameter("uaf_obb_start_response", uaf_obb_start_response) - identity.setWorkingParameter("qr_image", uaf_obb_start_response_json["modeResult"]["qrCode"]["qrImage"]) - identity.setWorkingParameter("uaf_obb_status_request", uaf_obb_status_request) - - return True - else: - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - return Arrays.asList("uaf_auth_method", "uaf_obb_auth_method", "uaf_obb_server_uri", "uaf_obb_start_response") - - def getCountAuthenticationSteps(self, configurationAttributes): - return 2 - - def getPageForStep(self, configurationAttributes, step): - if (step == 2): - return "/auth/uaf/login.xhtml" - - return "" - - def getNextStep(self, configurationAttributes, requestParameters, step): - return -1 - - def getLogoutExternalUrl(self, configurationAttributes, requestParameters): - print "Get external logout URL call" - return None - - def logout(self, configurationAttributes, requestParameters): - return True - - def setRequestScopedParameters(self, identity): - if self.registration_uri != None: - identity.setWorkingParameter("external_registration_uri", self.registration_uri) - identity.setWorkingParameter("qr_options", self.customQrOptions) - - def processBasicAuthentication(self, credentials): - userService = CdiUtil.bean(UserService) - authenticationService = CdiUtil.bean(AuthenticationService) - - user_name = credentials.getUsername() - user_password = credentials.getPassword() - - logged_in = False - if StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password): - logged_in = authenticationService.authenticate(user_name, user_password) - - if not logged_in: - return None - - find_user_by_uid = authenticationService.getAuthenticatedUser() - if find_user_by_uid == None: - print "UAF. Process basic authentication. Failed to find user '%s'" % user_name - return None - - return find_user_by_uid - - def findEnrollments(self, credentials): - result = [] - - userService = CdiUtil.bean(UserService) - user_name = credentials.getUsername() - user = userService.getUser(user_name, "oxExternalUid") - if user == None: - print "UAF. Find enrollments. Failed to find user" - return result - - user_custom_ext_attribute = userService.getCustomAttribute(user, "oxExternalUid") - if user_custom_ext_attribute == None: - return result - - uaf_prefix = "uaf:" - uaf_prefix_length = len(uaf_prefix) - for user_external_uid in user_custom_ext_attribute.getValues(): - index = user_external_uid.find(uaf_prefix) - if index != -1: - enrollment_uid = user_external_uid[uaf_prefix_length:] - result.append(enrollment_uid) - - return result - - def executePost(self, request_uri, request_data): - httpService = CdiUtil.bean(HttpService) - - request_headers = { "Content-type" : "application/json; charset=UTF-8", "Accept" : "application/json" } - - try: - http_service_response = httpService.executePost(self.http_client, request_uri, None, request_headers, request_data) - http_response = http_service_response.getHttpResponse() - except: - print "UAF. Validate POST response. Exception: ", sys.exc_info()[1] - return None - - try: - if not httpService.isResponseStastusCodeOk(http_response): - print "UAF. Validate POST response. Get invalid response from server: %s" % str(http_response.getStatusLine().getStatusCode()) - httpService.consume(http_response) - return None - - response_bytes = httpService.getResponseContent(http_response) - response_string = httpService.convertEntityToString(response_bytes) - httpService.consume(http_response) - - return response_string - finally: - http_service_response.closeConnection() - return None diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/gluu_uaf_integration_authentication_workflow.png b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/gluu_uaf_integration_authentication_workflow.png deleted file mode 100644 index c247c7641e708987fad8ae7c2e958ce90ec629b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59443 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�*(c*zNP6= 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 v+49zPcLJ0bi3!*azy5yC<)z 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

t}9Wkt>5D7+qQ`Oy%&BLjE~&B9Za&qesvezEDSS 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 diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/oob_qr_code.png b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/uaf/img/oob_qr_code.png deleted file mode 100644 index ce0716ef00c1329964586a6fd4d4e84a5efa75a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77419 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: Open RP URL -Browser->RP: Protected resource -RP->Gluu Server: Start AuthZ & AuthN -Gluu Server->UAF Script: Start User/Password + UAF -UAF Script->UAF Script: 1) Verify user/password -UAF Script->Nok Nok Server: START_OOB -Nok Nok Server->UAF Script: QR code for mobile application -UAF Script->Browser: 2) Render UAF login page with QR code - -Person->UAF Mobile: Start UAF application -UAF Mobile->Browser: Scan QR code -UAF Mobile->Nok Nok Server: INIT_OBB -Person->UAF Mobile: Biometric authentication -UAF Mobile->Nok Nok Server: FINISH_OBB - -Browser->Nok Nok Server: STATUS_OBB with delay 5 seconds -Browser->UAF Script: 3) Send response -UAF Script->Nok Nok Server: STATUS_OBB -UAF Script->Nok Nok Server: CANCEL_OBB if UAF authentication failed - -RP->Gluu Server: Request authorization -RP->Gluu Server: Request tokens -RP->Gluu Server: Request user_info diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidlogin.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidlogin.xhtml deleted file mode 100644 index 22fa40fce63..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidlogin.xhtml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - #{msgs['wikid.pageTitle']} - - - - - - -
-
- - - - - -
-
- -
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidregister.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidregister.xhtml deleted file mode 100644 index 9a395184c45..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wikid/wikidregister.xhtml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - #{msgs['wikid.pageTitle']} - - - - - - -
-
- - - - - -
-
- -
-
\ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/README.md b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/README.md deleted file mode 100644 index 62b46b60745..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# WWPass integration for Gluu - -[WWPass](https://wwpass.com/) replaces the traditional username and password -login with a more advanced multi-factor authentication solution. WWPass employs -strong cryptography and robust combination of authentication factors to deliver -a secure and user-friendly authentication experience. WWPass authentication -starts with a smartphone app or a hardware token as the first authentication -factor. Then additional authentication factors such as PIN or biometrics can be -added to verify the user identity further. - -## Installation - -To install WWPass support in Gluu server refer to [INSTALLATION.md](INSTALLATION.md). - -To install additional components refer to main wwpass-gluu repository at https://github.com/wwpass/gluu - -## Contacts - -Feel free to contact WWPass at support@wwpass.com if you have trouble integrating WWPass in your Gluu setup \ No newline at end of file diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/checkemail.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/checkemail.xhtml deleted file mode 100644 index 59f10a80bc7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/checkemail.xhtml +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -

- - - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpass.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpass.xhtml deleted file mode 100644 index 8330f86c4b7..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpass.xhtml +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpassbind.xhtml b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpassbind.xhtml deleted file mode 100644 index 2b93995aabc..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/pages/auth/wwpass/wwpassbind.xhtml +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - - - - - - - - - - - - - - -
-
-
-

#{identity.getWorkingParameter('errors')}

-
- -
- -
- - -
- -
- -
- - -
- - -
- -
- - -
- - -
-
-
-
- -
-
- - - -
-
- -
-

You presented a new WWPass Key, not associated with any account. If you already have an account, and need to replace your WWPass Key, please follow this link.

-
-
-
-
- - - -
- -
- diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/static/js/wwpass-frontend.js b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/static/js/wwpass-frontend.js deleted file mode 100644 index aeb1d82d55a..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/static/js/wwpass-frontend.js +++ /dev/null @@ -1,6097 +0,0 @@ -(function () { - 'use strict'; - - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - } - - var classCallCheck = _classCallCheck; - - function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - var createClass = _createClass; - - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - } - - var defineProperty = _defineProperty; - - function _objectSpread(target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i] != null ? arguments[i] : {}; - var ownKeys = Object.keys(Object(source)); - - if (typeof Object.getOwnPropertySymbols === 'function') { - ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { - return Object.getOwnPropertyDescriptor(source, sym).enumerable; - })); - } - - ownKeys.forEach(function (key) { - defineProperty(target, key, source[key]); - }); - } - - return target; - } - - var objectSpread = _objectSpread; - - /* Constants */ - - /* Status codes */ - var WWPASS_OK_MSG = 'OK'; - var WWPASS_STATUS = { - CONTINUE: 100, - OK: 200, - INTERNAL_ERROR: 400, - ALREADY_PERSONALIZED: 401, - PASSWORD_MISMATCH: 402, - PASSWORD_LOCKOUT: 403, - WRONG_KEY: 404, - WRONG_KEY_SECOND: 405, - NOT_A_KEY: 406, - NOT_A_KEY_SECOND: 407, - KEY_DISABLED: 408, - NOT_ALLOWED: 409, - BLANK_TOKEN: 410, - BLANK_SECOND_TOKEN: 411, - ACTIVITY_PROFILE_LOCKED: 412, - SSL_REQUIRED: 413, - BLANK_NORMAL_TOKEN: 414, - BLANK_SECOND_NORMAL_TOKEN: 415, - BLANK_MASTER_TOKEN: 416, - BLANK_SECOND_MASTER_TOKEN: 417, - NOT_ACTIVATED_TOKEN: 418, - NOT_ACTIVATED_SECOND_TOKEN: 419, - WRONG_KEY_SET: 420, - NO_VERIFIER: 421, - INCOMPLETE_KEYSET: 422, - INVALID_TICKET: 423, - SAME_TOKEN: 424, - NO_RECOVERY_INFO: 425, - BAD_RECOVERY_REQUEST: 426, - RECOVERY_FAILED: 427, - TERMINAL_ERROR: 500, - TERMINAL_NOT_FOUND: 501, - TERMINAL_BAD_REQUEST: 502, - NO_CONNECTION: 503, - NETWORK_ERROR: 504, - PROTOCOL_ERROR: 505, - UNKNOWN_HANDLER: 506, - TERMINAL_CANCELED: 590, - TIMEOUT: 600, - TICKET_TIMEOUT: 601, - USER_REJECT: 603, - NO_AUTH_INTERFACES_FOUND: 604, - TERMINAL_TIMEOUT: 605, - UNSUPPORTED_PLATFORM: 606 - }; - var WWPASS_NO_AUTH_INTERFACES_FOUND_MSG = 'No WWPass SecurityPack is found on your computer or WWPass Browser Plugin is disabled'; - var WWPASS_UNSUPPORTED_PLATFORM_MSG_TMPL = 'WWPass authentication is not supported on'; - var WWPASS_KEY_TYPE_PASSKEY = 'passkey'; - var WWPASS_KEY_TYPE_DEFAULT = WWPASS_KEY_TYPE_PASSKEY; - - var getCallbackURL = function getCallbackURL() { - var initialOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var defaultOptions = { - ppx: 'wwp_', - version: 2, - status: 200, - reason: 'OK', - ticket: undefined, - callbackURL: undefined, - hw: false // hardware legacy - - }; - - var options = objectSpread({}, defaultOptions, initialOptions); - - var url = ''; - - if (typeof options.callbackURL === 'string') { - url = options.callbackURL; - } - - var firstDelimiter = url.indexOf('?') === -1 ? '?' : '&'; - url += "".concat(firstDelimiter + encodeURIComponent(options.ppx), "version=").concat(options.version); - url += "&".concat(encodeURIComponent(options.ppx), "ticket=").concat(encodeURIComponent(options.ticket)); - url += "&".concat(encodeURIComponent(options.ppx), "status=").concat(encodeURIComponent(options.status)); - url += "&".concat(encodeURIComponent(options.ppx), "reason=").concat(encodeURIComponent(options.reason)); - - if (options.hw) { - url += "&".concat(encodeURIComponent(options.ppx), "hw=1"); - } - - return url; - }; - - var getUniversalURL = function getUniversalURL() { - var initialOptions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - var allowCallbackURL = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - var defaultOptions = { - universal: false, - operation: 'auth', - ppx: 'wwp_', - version: 2, - ticket: undefined, - callbackURL: undefined, - clientKey: undefined - }; - - var options = objectSpread({}, defaultOptions, initialOptions); - - var url = options.universal ? 'https://get.wwpass.com/' : 'wwpass://'; - - if (options.operation === 'auth') { - url += 'auth'; - url += "?v=".concat(options.version); - url += "&t=".concat(encodeURIComponent(options.ticket)); - url += "&ppx=".concat(encodeURIComponent(options.ppx)); - - if (options.clientKey) { - url += "&ck=".concat(options.clientKey); - } - - if (options.callbackURL && allowCallbackURL) { - url += "&c=".concat(encodeURIComponent(options.callbackURL)); - } - } else { - url += "".concat(encodeURIComponent(options.operation), "?t=").concat(encodeURIComponent(options.ticket)); - } - - return url; - }; - - var navigateToCallback = function navigateToCallback(options) { - if (typeof options.callbackURL === 'function') { - options.callbackURL(getCallbackURL(options)); - } else { - // URL string - window.location.href = getCallbackURL(options); - } - }; - - var connectionPool = []; - - var closeConnectionPool = function closeConnectionPool() { - while (connectionPool.length) { - var connection = connectionPool.shift(); - - if (connection.readyState === WebSocket.OPEN) { - connection.close(); - } - } - }; - - var applyDefaults = function applyDefaults(initialOptions) { - var defaultOptions = { - ppx: 'wwp_', - version: 2, - ticket: undefined, - callbackURL: undefined, - returnErrors: false, - log: function log() {}, - development: false, - spfewsAddress: 'wss://spfews.wwpass.com', - echo: undefined, - clientKeyOnly: false - }; - return objectSpread({}, defaultOptions, initialOptions); - }; - /** - * WWPass SPFE WebSocket connection - * @param {object} options - * - * options = { - * 'ticket': undefined, // stirng - * 'callbackURL': undefined, //string - * 'development': false || 'string' , // work with another spfews.wwpass.* server - * 'log': function (message) || console.log, // another log handler - * 'echo': undefined - * } - */ - - - var getWebSocketResult = function getWebSocketResult(initialOptions) { - return new Promise(function (resolve, reject) { - var options = applyDefaults(initialOptions); - var clientKey = null; - var originalTicket = options.ticket; - var ttl = null; - - var settle = function settle(status, reason) { - if (status === 200) { - var result = { - ppx: options.ppx, - version: options.version, - status: status, - reason: WWPASS_OK_MSG, - ticket: options.ticket, - callbackURL: options.callbackURL, - clientKey: clientKey, - originalTicket: originalTicket, - ttl: ttl - }; - - if (!options.clientKeyOnly) { - navigateToCallback(result); - } - - resolve(result); - } else { - var err = { - ppx: options.ppx, - version: options.version, - status: status, - reason: reason, - ticket: options.ticket, - callbackURL: options.callbackURL - }; - - if ((status === WWPASS_STATUS.INTERNAL_ERROR || options.returnErrors) && !options.clientKeyOnly) { - navigateToCallback(err); - } - - reject(err); - } - }; - - if (!('WebSocket' in window)) { - settle(WWPASS_STATUS.INTERNAL_ERROR, 'WebSocket is not supported.'); - return; - } - - var websocketurl = options.spfewsAddress; - var socket = new WebSocket(websocketurl); - connectionPool.push(socket); - var log = options.log; - - socket.onopen = function () { - try { - log("Connected: ".concat(websocketurl)); - var message = JSON.stringify({ - ticket: options.ticket - }); - log("Sent message to server: ".concat(message)); - socket.send(message); - } catch (error) { - log(error); - settle(WWPASS_STATUS.INTERNAL_ERROR, 'WebSocket error'); - } - }; - - socket.onclose = function () { - try { - var index = connectionPool.indexOf(socket); - - if (index !== -1) { - connectionPool.splice(index, 1); - } - - log('Disconnected'); - resolve({ - refresh: true - }); - } catch (error) { - log(error); - settle(WWPASS_STATUS.INTERNAL_ERROR, 'WebSocket error'); - } - }; - - socket.onmessage = function (message) { - try { - log("Message received from server: ".concat(message.data)); - var response = JSON.parse(message.data); - var status = response.code; - var reason = response.reason; - - if ('clientKey' in response && !clientKey) { - clientKey = response.clientKey; - - if (response.originalTicket !== undefined) { - originalTicket = response.originalTicket; - ttl = response.ttl; - } - } - - if (status === 100) { - return; - } - - settle(status, reason); - socket.close(); - } catch (error) { - log(error); - settle(WWPASS_STATUS.INTERNAL_ERROR, 'WebSocket error'); - } - }; - }); - }; - - var abToB64 = function abToB64(data) { - return btoa(String.fromCharCode.apply(null, new Uint8Array(data))); - }; - - var b64ToAb = function b64ToAb(base64) { - var s = atob(base64); - var bytes = new Uint8Array(s.length); - - for (var i = 0; i < s.length; i += 1) { - bytes[i] = s.charCodeAt(i); - } - - return bytes.buffer; - }; - - var ab2str = function ab2str(buf) { - return String.fromCharCode.apply(null, new Uint16Array(buf)); - }; - - var str2ab = function str2ab(str) { - var buf = new ArrayBuffer(str.length * 2); // 2 bytes for each char - - var bufView = new Uint16Array(buf); - - for (var i = 0, strLen = str.length; i < strLen; i += 1) { - bufView[i] = str.charCodeAt(i); - } - - return buf; - }; - - var crypto = window.crypto || window.msCrypto; - var subtle = crypto ? crypto.webkitSubtle || crypto.subtle : null; - - var encodeClientKey = function encodeClientKey(key) { - return abToB64(key).replace(/\+/g, '-').replace(/[/]/g, '.').replace(/=/g, '_'); - }; - - var encrypt = function encrypt(options, key, data) { - return subtle.encrypt(options, key, data); - }; - - var decrypt = function decrypt(options, key, data) { - return subtle.decrypt(options, key, data); - }; - - var importKey = function importKey(format, key, algoritm, extractable, operations) { - return subtle.importKey(format, key, algoritm, extractable, operations); - }; // eslint-disable-line max-len - - - var getRandomData = function getRandomData(buffer) { - return crypto.getRandomValues(buffer); - }; - - var concatBuffers = function concatBuffers() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var totalLen = args.reduce(function (accumulator, curentAB) { - return accumulator + curentAB.byteLength; - }, 0); - var i = 0; - var result = new Uint8Array(totalLen); - - while (args.length > 0) { - result.set(new Uint8Array(args[0]), i); - i += args[0].byteLength; - args.shift(); - } - - return result.buffer; - }; - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - var arrayWithHoles = _arrayWithHoles; - - function _iterableToArrayLimit(arr, i) { - if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { - return; - } - - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - var iterableToArrayLimit = _iterableToArrayLimit; - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - - var nonIterableRest = _nonIterableRest; - - function _slicedToArray(arr, i) { - return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || nonIterableRest(); - } - - var slicedToArray = _slicedToArray; - - var isClientKeyTicket = function isClientKeyTicket(ticket) { - var _ticket$split = ticket.split('@'), - _ticket$split2 = slicedToArray(_ticket$split, 1), - info = _ticket$split2[0]; - - var spnameFlagsOTP = info.split(':'); - - if (spnameFlagsOTP.length < 3) { - return false; - } - - var FLAGS_INDEX = 1; // second element of ticket — flags - - var flags = spnameFlagsOTP[FLAGS_INDEX]; - return flags.split('').some(function (element) { - return element === 'c'; - }); - }; - - var ticketAdapter = function ticketAdapter(response) { - if (response && response.data) { - var ticket = { - ticket: response.data, - ttl: response.ttl || 120 - }; - delete ticket.data; - return ticket; - } - - return response; - }; - - function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; - } - - var _typeof_1 = createCommonjsModule(function (module) { - function _typeof(obj) { - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - module.exports = _typeof = function _typeof(obj) { - return typeof obj; - }; - } else { - module.exports = _typeof = function _typeof(obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - module.exports = _typeof; - }); - - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - var assertThisInitialized = _assertThisInitialized; - - function _possibleConstructorReturn(self, call) { - if (call && (_typeof_1(call) === "object" || typeof call === "function")) { - return call; - } - - return assertThisInitialized(self); - } - - var possibleConstructorReturn = _possibleConstructorReturn; - - var getPrototypeOf = createCommonjsModule(function (module) { - function _getPrototypeOf(o) { - module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _getPrototypeOf(o); - } - - module.exports = _getPrototypeOf; - }); - - var setPrototypeOf = createCommonjsModule(function (module) { - function _setPrototypeOf(o, p) { - module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { - o.__proto__ = p; - return o; - }; - - return _setPrototypeOf(o, p); - } - - module.exports = _setPrototypeOf; - }); - - function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - if (superClass) setPrototypeOf(subClass, superClass); - } - - var inherits = _inherits; - - function _isNativeFunction(fn) { - return Function.toString.call(fn).indexOf("[native code]") !== -1; - } - - var isNativeFunction = _isNativeFunction; - - var construct = createCommonjsModule(function (module) { - function isNativeReflectConstruct() { - if (typeof Reflect === "undefined" || !Reflect.construct) return false; - if (Reflect.construct.sham) return false; - if (typeof Proxy === "function") return true; - - try { - Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); - return true; - } catch (e) { - return false; - } - } - - function _construct(Parent, args, Class) { - if (isNativeReflectConstruct()) { - module.exports = _construct = Reflect.construct; - } else { - module.exports = _construct = function _construct(Parent, args, Class) { - var a = [null]; - a.push.apply(a, args); - var Constructor = Function.bind.apply(Parent, a); - var instance = new Constructor(); - if (Class) setPrototypeOf(instance, Class.prototype); - return instance; - }; - } - - return _construct.apply(null, arguments); - } - - module.exports = _construct; - }); - - var wrapNativeSuper = createCommonjsModule(function (module) { - function _wrapNativeSuper(Class) { - var _cache = typeof Map === "function" ? new Map() : undefined; - - module.exports = _wrapNativeSuper = function _wrapNativeSuper(Class) { - if (Class === null || !isNativeFunction(Class)) return Class; - - if (typeof Class !== "function") { - throw new TypeError("Super expression must either be null or a function"); - } - - if (typeof _cache !== "undefined") { - if (_cache.has(Class)) return _cache.get(Class); - - _cache.set(Class, Wrapper); - } - - function Wrapper() { - return construct(Class, arguments, getPrototypeOf(this).constructor); - } - - Wrapper.prototype = Object.create(Class.prototype, { - constructor: { - value: Wrapper, - enumerable: false, - writable: true, - configurable: true - } - }); - return setPrototypeOf(Wrapper, Class); - }; - - return _wrapNativeSuper(Class); - } - - module.exports = _wrapNativeSuper; - }); - - var WWPassError = - /*#__PURE__*/ - function (_Error) { - inherits(WWPassError, _Error); - - function WWPassError(code) { - var _this; - - classCallCheck(this, WWPassError); - - for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - args[_key - 1] = arguments[_key]; - } - - _this = possibleConstructorReturn(this, getPrototypeOf(WWPassError).call(this, args, WWPassError)); - Error.captureStackTrace(assertThisInitialized(_this), WWPassError); - _this.code = code; - return _this; - } - - createClass(WWPassError, [{ - key: "toString", - value: function toString() { - return "".concat(this.name, "(").concat(this.code, "): ").concat(this.message); - } - }]); - - return WWPassError; - }(wrapNativeSuper(Error)); - - var exportKey = function exportKey(type, key) { - return subtle.exportKey(type, key); - }; // generate digest from string - - - var hex = function hex(buffer) { - var hexCodes = []; - var view = new DataView(buffer); - - for (var i = 0; i < view.byteLength; i += 4) { - // Using getUint32 reduces the number of iterations needed (we process 4 bytes each time) - var value = view.getUint32(i); // toString(16) will give the hex representation of the number without padding - - var stringValue = value.toString(16); // We use concatenation and slice for padding - - var padding = '00000000'; - var paddedValue = (padding + stringValue).slice(-padding.length); - hexCodes.push(paddedValue); - } // Join all the hex strings into one - - - return hexCodes.join(''); - }; // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest - - - var sha256 = function sha256(str) { - // We transform the string into an arraybuffer. - var buffer = str2ab(str); - return subtle.digest({ - name: 'SHA-256' - }, buffer).then(function (hash) { - return hex(hash); - }); - }; - - var clean = function clean(items) { - var currentDate = window.Date.now(); - return items.filter(function (item) { - return item.deadline > currentDate; - }); - }; - - var loadNonces = function loadNonces() { - var wwpassNonce = window.localStorage.getItem('wwpassNonce'); - - if (!wwpassNonce) { - return []; - } - - try { - return clean(JSON.parse(wwpassNonce)); - } catch (error) { - window.localStorage.removeItem('wwpassNonce'); - throw error; - } - }; - - var saveNonces = function saveNonces(nonces) { - window.localStorage.setItem('wwpassNonce', JSON.stringify(nonces)); - }; // get from localStorage Client Nonce - - - var getClientNonce = function getClientNonce(ticket) { - var newTTL = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; - - if (!subtle) { - throw new WWPassError(WWPASS_STATUS.SSL_REQUIRED, 'Client-side encryption requires https.'); - } - - var nonces = loadNonces(); - return sha256(ticket).then(function (hash) { - var nonce = nonces.find(function (it) { - return hash === it.hash; - }); - var key = nonce && nonce.key ? b64ToAb(nonce.key) : undefined; - - if (newTTL && key) { - nonce.deadline = window.Date.now() + newTTL * 1000; - saveNonces(nonces); - } - - return key; - }); - }; // generate Client Nonce and set it to localStorage - - - var generateClientNonce = function generateClientNonce(ticket) { - var ttl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 120; - - if (!subtle) { - throw new WWPassError(WWPASS_STATUS.SSL_REQUIRED, 'Client-side encryption requires https.'); - } - - return getClientNonce(ticket).then(function (loadedKey) { - if (loadedKey) { - return loadedKey; - } - - return subtle.generateKey({ - name: 'AES-CBC', - length: 256 - }, true, // is extractable - ['encrypt', 'decrypt']).then(function (key) { - return exportKey('raw', key); - }).then(function (rawKey) { - return sha256(ticket).then(function (digest) { - var nonce = { - hash: digest, - key: abToB64(rawKey), - deadline: window.Date.now() + ttl * 1000 - }; - var nonces = loadNonces(); - nonces.push(nonce); - saveNonces(nonces); // hack for return key - - return rawKey; - }); - }); - }); - }; - - var getClientNonceWrapper = function getClientNonceWrapper(ticket) { - var ttl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 120; - - if (!isClientKeyTicket(ticket)) { - return new Promise(function (resolve) { - resolve(undefined); - }); - } - - return generateClientNonce(ticket, ttl); - }; - - var copyClientNonce = function copyClientNonce(oldTicket, newTicket, ttl) { - return getClientNonce(oldTicket).then(function (nonceKey) { - return sha256(newTicket) // eslint-disable-line max-len - .then(function (digest) { - var nonces = loadNonces(); - nonces.push({ - hash: digest, - key: abToB64(nonceKey), - deadline: window.Date.now() + ttl * 1000 - }); - saveNonces(nonces); - }); - }); - }; - - var clientKeyIV = new Uint8Array([176, 178, 97, 142, 156, 31, 45, 30, 81, 210, 85, 14, 202, 203, 86, 240]); - - var WWPassCryptoPromise = - /*#__PURE__*/ - function () { - createClass(WWPassCryptoPromise, [{ - key: "encryptArrayBuffer", - value: function encryptArrayBuffer(arrayBuffer) { - var iv = new Uint8Array(this.ivLen); - getRandomData(iv); - var algorithm = this.algorithm; - Object.assign(algorithm, { - iv: iv - }); - return encrypt(algorithm, this.clientKey, arrayBuffer).then(function (encryptedAB) { - return concatBuffers(iv.buffer, encryptedAB); - }); - } - }, { - key: "encryptString", - value: function encryptString(string) { - return this.encryptArrayBuffer(str2ab(string)).then(abToB64); - } - }, { - key: "decryptArrayBuffer", - value: function decryptArrayBuffer(encryptedArrayBuffer) { - var algorithm = this.algorithm; - Object.assign(algorithm, { - iv: encryptedArrayBuffer.slice(0, this.ivLen) - }); - return decrypt(algorithm, this.clientKey, encryptedArrayBuffer.slice(this.ivLen)); - } - }, { - key: "decryptString", - value: function decryptString(encryptedString) { - return this.decryptArrayBuffer(b64ToAb(encryptedString)).then(ab2str); - } // Private - - }], [{ - key: "getWWPassCrypto", - - /* Return Promise that will be resloved to catual crypto object - with encrypt/decrypt String/ArrayBuffer methods and cleintKey member. - Ticket must be authenticated with 'c' auth factor. - Only supported values for algorithm are 'AES-GCM' and 'AES-CBC'. - */ - value: function getWWPassCrypto(ticket) { - var algorithmName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'AES-GCM'; - var encryptedClientKey = null; - var algorithm = { - name: algorithmName, - length: 256 - }; - return getWebSocketResult({ - ticket: ticket, - clientKeyOnly: true - }).then(function (result) { - if (!result.clientKey) { - throw Error("No client key associated with the ticket ".concat(ticket)); - } - - encryptedClientKey = result.clientKey; - return getClientNonce(result.originalTicket ? result.originalTicket : ticket, result.ttl); - }).then(function (key) { - if (!key) { - throw new Error('No client key nonce associated with the ticket in this browser'); - } - - return importKey('raw', key, { - name: 'AES-CBC' - }, false, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']); - }).then(function (clientKeyNonce) { - return decrypt({ - name: 'AES-CBC', - iv: clientKeyIV - }, clientKeyNonce, b64ToAb(encryptedClientKey)); - }).then(function (arrayBuffer) { - return importKey('raw', arrayBuffer, algorithm, false, ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey']); - }).then(function (key) { - return new WWPassCryptoPromise(key, algorithm); - }).catch(function (error) { - if (error.reason !== undefined) { - throw new Error(error.reason); - } - - throw error; - }); - } - }]); - - function WWPassCryptoPromise(key, algorithm) { - classCallCheck(this, WWPassCryptoPromise); - - this.ivLen = algorithm.name === 'AES-GCM' ? 12 : 16; - this.algorithm = algorithm; - - if (algorithm.name === 'AES-GCM') { - Object.assign(this.algorithm, { - tagLength: 128 - }); - } - - this.clientKey = key; - } - - return WWPassCryptoPromise; - }(); - - var runtime_1 = createCommonjsModule(function (module) { - /** - * Copyright (c) 2014-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - var runtime = (function (exports) { - - var Op = Object.prototype; - var hasOwn = Op.hasOwnProperty; - var undefined$1; // More compressible than void 0. - var $Symbol = typeof Symbol === "function" ? Symbol : {}; - var iteratorSymbol = $Symbol.iterator || "@@iterator"; - var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator"; - var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; - - function wrap(innerFn, outerFn, self, tryLocsList) { - // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator. - var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator; - var generator = Object.create(protoGenerator.prototype); - var context = new Context(tryLocsList || []); - - // The ._invoke method unifies the implementations of the .next, - // .throw, and .return methods. - generator._invoke = makeInvokeMethod(innerFn, self, context); - - return generator; - } - exports.wrap = wrap; - - // Try/catch helper to minimize deoptimizations. Returns a completion - // record like context.tryEntries[i].completion. This interface could - // have been (and was previously) designed to take a closure to be - // invoked without arguments, but in all the cases we care about we - // already have an existing method we want to call, so there's no need - // to create a new function object. We can even get away with assuming - // the method takes exactly one argument, since that happens to be true - // in every case, so we don't have to touch the arguments object. The - // only additional allocation required is the completion record, which - // has a stable shape and so hopefully should be cheap to allocate. - function tryCatch(fn, obj, arg) { - try { - return { type: "normal", arg: fn.call(obj, arg) }; - } catch (err) { - return { type: "throw", arg: err }; - } - } - - var GenStateSuspendedStart = "suspendedStart"; - var GenStateSuspendedYield = "suspendedYield"; - var GenStateExecuting = "executing"; - var GenStateCompleted = "completed"; - - // Returning this object from the innerFn has the same effect as - // breaking out of the dispatch switch statement. - var ContinueSentinel = {}; - - // Dummy constructor functions that we use as the .constructor and - // .constructor.prototype properties for functions that return Generator - // objects. For full spec compliance, you may wish to configure your - // minifier not to mangle the names of these two functions. - function Generator() {} - function GeneratorFunction() {} - function GeneratorFunctionPrototype() {} - - // This is a polyfill for %IteratorPrototype% for environments that - // don't natively support it. - var IteratorPrototype = {}; - IteratorPrototype[iteratorSymbol] = function () { - return this; - }; - - var getProto = Object.getPrototypeOf; - var NativeIteratorPrototype = getProto && getProto(getProto(values([]))); - if (NativeIteratorPrototype && - NativeIteratorPrototype !== Op && - hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) { - // This environment has a native %IteratorPrototype%; use it instead - // of the polyfill. - IteratorPrototype = NativeIteratorPrototype; - } - - var Gp = GeneratorFunctionPrototype.prototype = - Generator.prototype = Object.create(IteratorPrototype); - GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype; - GeneratorFunctionPrototype.constructor = GeneratorFunction; - GeneratorFunctionPrototype[toStringTagSymbol] = - GeneratorFunction.displayName = "GeneratorFunction"; - - // Helper for defining the .next, .throw, and .return methods of the - // Iterator interface in terms of a single ._invoke method. - function defineIteratorMethods(prototype) { - ["next", "throw", "return"].forEach(function(method) { - prototype[method] = function(arg) { - return this._invoke(method, arg); - }; - }); - } - - exports.isGeneratorFunction = function(genFun) { - var ctor = typeof genFun === "function" && genFun.constructor; - return ctor - ? ctor === GeneratorFunction || - // For the native GeneratorFunction constructor, the best we can - // do is to check its .name property. - (ctor.displayName || ctor.name) === "GeneratorFunction" - : false; - }; - - exports.mark = function(genFun) { - if (Object.setPrototypeOf) { - Object.setPrototypeOf(genFun, GeneratorFunctionPrototype); - } else { - genFun.__proto__ = GeneratorFunctionPrototype; - if (!(toStringTagSymbol in genFun)) { - genFun[toStringTagSymbol] = "GeneratorFunction"; - } - } - genFun.prototype = Object.create(Gp); - return genFun; - }; - - // Within the body of any async function, `await x` is transformed to - // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test - // `hasOwn.call(value, "__await")` to determine if the yielded value is - // meant to be awaited. - exports.awrap = function(arg) { - return { __await: arg }; - }; - - function AsyncIterator(generator) { - function invoke(method, arg, resolve, reject) { - var record = tryCatch(generator[method], generator, arg); - if (record.type === "throw") { - reject(record.arg); - } else { - var result = record.arg; - var value = result.value; - if (value && - typeof value === "object" && - hasOwn.call(value, "__await")) { - return Promise.resolve(value.__await).then(function(value) { - invoke("next", value, resolve, reject); - }, function(err) { - invoke("throw", err, resolve, reject); - }); - } - - return Promise.resolve(value).then(function(unwrapped) { - // When a yielded Promise is resolved, its final value becomes - // the .value of the Promise<{value,done}> result for the - // current iteration. - result.value = unwrapped; - resolve(result); - }, function(error) { - // If a rejected Promise was yielded, throw the rejection back - // into the async generator function so it can be handled there. - return invoke("throw", error, resolve, reject); - }); - } - } - - var previousPromise; - - function enqueue(method, arg) { - function callInvokeWithMethodAndArg() { - return new Promise(function(resolve, reject) { - invoke(method, arg, resolve, reject); - }); - } - - return previousPromise = - // If enqueue has been called before, then we want to wait until - // all previous Promises have been resolved before calling invoke, - // so that results are always delivered in the correct order. If - // enqueue has not been called before, then it is important to - // call invoke immediately, without waiting on a callback to fire, - // so that the async generator function has the opportunity to do - // any necessary setup in a predictable way. This predictability - // is why the Promise constructor synchronously invokes its - // executor callback, and why async functions synchronously - // execute code before the first await. Since we implement simple - // async functions in terms of async generators, it is especially - // important to get this right, even though it requires care. - previousPromise ? previousPromise.then( - callInvokeWithMethodAndArg, - // Avoid propagating failures to Promises returned by later - // invocations of the iterator. - callInvokeWithMethodAndArg - ) : callInvokeWithMethodAndArg(); - } - - // Define the unified helper method that is used to implement .next, - // .throw, and .return (see defineIteratorMethods). - this._invoke = enqueue; - } - - defineIteratorMethods(AsyncIterator.prototype); - AsyncIterator.prototype[asyncIteratorSymbol] = function () { - return this; - }; - exports.AsyncIterator = AsyncIterator; - - // Note that simple async functions are implemented on top of - // AsyncIterator objects; they just return a Promise for the value of - // the final result produced by the iterator. - exports.async = function(innerFn, outerFn, self, tryLocsList) { - var iter = new AsyncIterator( - wrap(innerFn, outerFn, self, tryLocsList) - ); - - return exports.isGeneratorFunction(outerFn) - ? iter // If outerFn is a generator, return the full iterator. - : iter.next().then(function(result) { - return result.done ? result.value : iter.next(); - }); - }; - - function makeInvokeMethod(innerFn, self, context) { - var state = GenStateSuspendedStart; - - return function invoke(method, arg) { - if (state === GenStateExecuting) { - throw new Error("Generator is already running"); - } - - if (state === GenStateCompleted) { - if (method === "throw") { - throw arg; - } - - // Be forgiving, per 25.3.3.3.3 of the spec: - // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume - return doneResult(); - } - - context.method = method; - context.arg = arg; - - while (true) { - var delegate = context.delegate; - if (delegate) { - var delegateResult = maybeInvokeDelegate(delegate, context); - if (delegateResult) { - if (delegateResult === ContinueSentinel) continue; - return delegateResult; - } - } - - if (context.method === "next") { - // Setting context._sent for legacy support of Babel's - // function.sent implementation. - context.sent = context._sent = context.arg; - - } else if (context.method === "throw") { - if (state === GenStateSuspendedStart) { - state = GenStateCompleted; - throw context.arg; - } - - context.dispatchException(context.arg); - - } else if (context.method === "return") { - context.abrupt("return", context.arg); - } - - state = GenStateExecuting; - - var record = tryCatch(innerFn, self, context); - if (record.type === "normal") { - // If an exception is thrown from innerFn, we leave state === - // GenStateExecuting and loop back for another invocation. - state = context.done - ? GenStateCompleted - : GenStateSuspendedYield; - - if (record.arg === ContinueSentinel) { - continue; - } - - return { - value: record.arg, - done: context.done - }; - - } else if (record.type === "throw") { - state = GenStateCompleted; - // Dispatch the exception by looping back around to the - // context.dispatchException(context.arg) call above. - context.method = "throw"; - context.arg = record.arg; - } - } - }; - } - - // Call delegate.iterator[context.method](context.arg) and handle the - // result, either by returning a { value, done } result from the - // delegate iterator, or by modifying context.method and context.arg, - // setting context.delegate to null, and returning the ContinueSentinel. - function maybeInvokeDelegate(delegate, context) { - var method = delegate.iterator[context.method]; - if (method === undefined$1) { - // A .throw or .return when the delegate iterator has no .throw - // method always terminates the yield* loop. - context.delegate = null; - - if (context.method === "throw") { - // Note: ["return"] must be used for ES3 parsing compatibility. - if (delegate.iterator["return"]) { - // If the delegate iterator has a return method, give it a - // chance to clean up. - context.method = "return"; - context.arg = undefined$1; - maybeInvokeDelegate(delegate, context); - - if (context.method === "throw") { - // If maybeInvokeDelegate(context) changed context.method from - // "return" to "throw", let that override the TypeError below. - return ContinueSentinel; - } - } - - context.method = "throw"; - context.arg = new TypeError( - "The iterator does not provide a 'throw' method"); - } - - return ContinueSentinel; - } - - var record = tryCatch(method, delegate.iterator, context.arg); - - if (record.type === "throw") { - context.method = "throw"; - context.arg = record.arg; - context.delegate = null; - return ContinueSentinel; - } - - var info = record.arg; - - if (! info) { - context.method = "throw"; - context.arg = new TypeError("iterator result is not an object"); - context.delegate = null; - return ContinueSentinel; - } - - if (info.done) { - // Assign the result of the finished delegate to the temporary - // variable specified by delegate.resultName (see delegateYield). - context[delegate.resultName] = info.value; - - // Resume execution at the desired location (see delegateYield). - context.next = delegate.nextLoc; - - // If context.method was "throw" but the delegate handled the - // exception, let the outer generator proceed normally. If - // context.method was "next", forget context.arg since it has been - // "consumed" by the delegate iterator. If context.method was - // "return", allow the original .return call to continue in the - // outer generator. - if (context.method !== "return") { - context.method = "next"; - context.arg = undefined$1; - } - - } else { - // Re-yield the result returned by the delegate method. - return info; - } - - // The delegate iterator is finished, so forget it and continue with - // the outer generator. - context.delegate = null; - return ContinueSentinel; - } - - // Define Generator.prototype.{next,throw,return} in terms of the - // unified ._invoke helper method. - defineIteratorMethods(Gp); - - Gp[toStringTagSymbol] = "Generator"; - - // A Generator should always return itself as the iterator object when the - // @@iterator function is called on it. Some browsers' implementations of the - // iterator prototype chain incorrectly implement this, causing the Generator - // object to not be returned from this call. This ensures that doesn't happen. - // See https://github.com/facebook/regenerator/issues/274 for more details. - Gp[iteratorSymbol] = function() { - return this; - }; - - Gp.toString = function() { - return "[object Generator]"; - }; - - function pushTryEntry(locs) { - var entry = { tryLoc: locs[0] }; - - if (1 in locs) { - entry.catchLoc = locs[1]; - } - - if (2 in locs) { - entry.finallyLoc = locs[2]; - entry.afterLoc = locs[3]; - } - - this.tryEntries.push(entry); - } - - function resetTryEntry(entry) { - var record = entry.completion || {}; - record.type = "normal"; - delete record.arg; - entry.completion = record; - } - - function Context(tryLocsList) { - // The root entry object (effectively a try statement without a catch - // or a finally block) gives us a place to store values thrown from - // locations where there is no enclosing try statement. - this.tryEntries = [{ tryLoc: "root" }]; - tryLocsList.forEach(pushTryEntry, this); - this.reset(true); - } - - exports.keys = function(object) { - var keys = []; - for (var key in object) { - keys.push(key); - } - keys.reverse(); - - // Rather than returning an object with a next method, we keep - // things simple and return the next function itself. - return function next() { - while (keys.length) { - var key = keys.pop(); - if (key in object) { - next.value = key; - next.done = false; - return next; - } - } - - // To avoid creating an additional object, we just hang the .value - // and .done properties off the next function object itself. This - // also ensures that the minifier will not anonymize the function. - next.done = true; - return next; - }; - }; - - function values(iterable) { - if (iterable) { - var iteratorMethod = iterable[iteratorSymbol]; - if (iteratorMethod) { - return iteratorMethod.call(iterable); - } - - if (typeof iterable.next === "function") { - return iterable; - } - - if (!isNaN(iterable.length)) { - var i = -1, next = function next() { - while (++i < iterable.length) { - if (hasOwn.call(iterable, i)) { - next.value = iterable[i]; - next.done = false; - return next; - } - } - - next.value = undefined$1; - next.done = true; - - return next; - }; - - return next.next = next; - } - } - - // Return an iterator with no values. - return { next: doneResult }; - } - exports.values = values; - - function doneResult() { - return { value: undefined$1, done: true }; - } - - Context.prototype = { - constructor: Context, - - reset: function(skipTempReset) { - this.prev = 0; - this.next = 0; - // Resetting context._sent for legacy support of Babel's - // function.sent implementation. - this.sent = this._sent = undefined$1; - this.done = false; - this.delegate = null; - - this.method = "next"; - this.arg = undefined$1; - - this.tryEntries.forEach(resetTryEntry); - - if (!skipTempReset) { - for (var name in this) { - // Not sure about the optimal order of these conditions: - if (name.charAt(0) === "t" && - hasOwn.call(this, name) && - !isNaN(+name.slice(1))) { - this[name] = undefined$1; - } - } - } - }, - - stop: function() { - this.done = true; - - var rootEntry = this.tryEntries[0]; - var rootRecord = rootEntry.completion; - if (rootRecord.type === "throw") { - throw rootRecord.arg; - } - - return this.rval; - }, - - dispatchException: function(exception) { - if (this.done) { - throw exception; - } - - var context = this; - function handle(loc, caught) { - record.type = "throw"; - record.arg = exception; - context.next = loc; - - if (caught) { - // If the dispatched exception was caught by a catch block, - // then let that catch block handle the exception normally. - context.method = "next"; - context.arg = undefined$1; - } - - return !! caught; - } - - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - var record = entry.completion; - - if (entry.tryLoc === "root") { - // Exception thrown outside of any try block that could handle - // it, so set the completion value of the entire function to - // throw the exception. - return handle("end"); - } - - if (entry.tryLoc <= this.prev) { - var hasCatch = hasOwn.call(entry, "catchLoc"); - var hasFinally = hasOwn.call(entry, "finallyLoc"); - - if (hasCatch && hasFinally) { - if (this.prev < entry.catchLoc) { - return handle(entry.catchLoc, true); - } else if (this.prev < entry.finallyLoc) { - return handle(entry.finallyLoc); - } - - } else if (hasCatch) { - if (this.prev < entry.catchLoc) { - return handle(entry.catchLoc, true); - } - - } else if (hasFinally) { - if (this.prev < entry.finallyLoc) { - return handle(entry.finallyLoc); - } - - } else { - throw new Error("try statement without catch or finally"); - } - } - } - }, - - abrupt: function(type, arg) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.tryLoc <= this.prev && - hasOwn.call(entry, "finallyLoc") && - this.prev < entry.finallyLoc) { - var finallyEntry = entry; - break; - } - } - - if (finallyEntry && - (type === "break" || - type === "continue") && - finallyEntry.tryLoc <= arg && - arg <= finallyEntry.finallyLoc) { - // Ignore the finally entry if control is not jumping to a - // location outside the try/catch block. - finallyEntry = null; - } - - var record = finallyEntry ? finallyEntry.completion : {}; - record.type = type; - record.arg = arg; - - if (finallyEntry) { - this.method = "next"; - this.next = finallyEntry.finallyLoc; - return ContinueSentinel; - } - - return this.complete(record); - }, - - complete: function(record, afterLoc) { - if (record.type === "throw") { - throw record.arg; - } - - if (record.type === "break" || - record.type === "continue") { - this.next = record.arg; - } else if (record.type === "return") { - this.rval = this.arg = record.arg; - this.method = "return"; - this.next = "end"; - } else if (record.type === "normal" && afterLoc) { - this.next = afterLoc; - } - - return ContinueSentinel; - }, - - finish: function(finallyLoc) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.finallyLoc === finallyLoc) { - this.complete(entry.completion, entry.afterLoc); - resetTryEntry(entry); - return ContinueSentinel; - } - } - }, - - "catch": function(tryLoc) { - for (var i = this.tryEntries.length - 1; i >= 0; --i) { - var entry = this.tryEntries[i]; - if (entry.tryLoc === tryLoc) { - var record = entry.completion; - if (record.type === "throw") { - var thrown = record.arg; - resetTryEntry(entry); - } - return thrown; - } - } - - // The context.catch method must only be called with a location - // argument that corresponds to a known catch block. - throw new Error("illegal catch attempt"); - }, - - delegateYield: function(iterable, resultName, nextLoc) { - this.delegate = { - iterator: values(iterable), - resultName: resultName, - nextLoc: nextLoc - }; - - if (this.method === "next") { - // Deliberately forget the last sent value so that we don't - // accidentally pass it on to the delegate. - this.arg = undefined$1; - } - - return ContinueSentinel; - } - }; - - // Regardless of whether this script is executing as a CommonJS module - // or not, return the runtime object so that we can declare the variable - // regeneratorRuntime in the outer scope, which allows this module to be - // injected easily by `bin/regenerator --include-runtime script.js`. - return exports; - - }( - // If this script is executing as a CommonJS module, use module.exports - // as the regeneratorRuntime namespace. Otherwise create a new empty - // object. Either way, the resulting object will be used to initialize - // the regeneratorRuntime variable at the top of this file. - module.exports - )); - - try { - regeneratorRuntime = runtime; - } catch (accidentalStrictMode) { - // This module should not be running in strict mode, so the above - // assignment should always work unless something is misconfigured. Just - // in case runtime.js accidentally runs in strict mode, we can escape - // strict mode using a global Function call. This could conceivably fail - // if a Content Security Policy forbids using Function, but in that case - // the proper solution is to fix the accidental strict mode problem. If - // you've misconfigured your bundler to force strict mode and applied a - // CSP to forbid Function, and you're not willing to fix either of those - // problems, please detail your unique predicament in a GitHub issue. - Function("r", "regeneratorRuntime = r")(runtime); - } - }); - - var regenerator = runtime_1; - - function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - - if (info.done) { - resolve(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - - function _asyncToGenerator(fn) { - return function () { - var self = this, - args = arguments; - return new Promise(function (resolve, reject) { - var gen = fn.apply(self, args); - - function _next(value) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); - } - - function _throw(err) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); - } - - _next(undefined); - }); - }; - } - - var asyncToGenerator = _asyncToGenerator; - - var noCacheHeaders = { - pragma: 'no-cache', - 'cache-control': 'no-cache' - }; - - var getTicket = function getTicket(url) { - return fetch(url, { - cache: 'no-store', - headers: noCacheHeaders - }).then(function (response) { - if (!response.ok) { - throw Error("Error fetching ticket from \"".concat(url, "\": ").concat(response.statusText)); - } - - return response.json(); - }); - }; - /* updateTicket should be called when the client wants to extend the session beyond - ticket's TTL. The URL handler on the server should use putTicket to get new ticket - whith the same credentials as the old one. The URL should return JSON object: - {"oldTicket": "", "newTicket": "", "ttl": } - The functions ultimately resolves to: - {"ticket": "", "ttl": } - */ - - - var updateTicket = function updateTicket(url) { - return fetch(url, { - cache: 'no-store', - headers: noCacheHeaders - }).then(function (response) { - if (!response.ok) { - throw Error("Error updating ticket from \"".concat(url, "\": ").concat(response.statusText)); - } - - return response.json(); - }).then(function (response) { - if (!response.newTicket || !response.oldTicket || !response.ttl) { - throw Error("Invalid response ot updateTicket: ".concat(response)); - } - - var result = { - ticket: response.newTicket, - ttl: response.ttl - }; - - if (!isClientKeyTicket(response.newTicket)) { - return result; - } // We have to call getWebSocketResult and getClientNonce to check for Nonce and update - // TTL on original ticket - - - return getWebSocketResult({ - ticket: response.newTicket, - clientKeyOnly: true - }).then(function (wsResult) { - if (!wsResult.clientKey) { - throw Error("No client key associated with the ticket ".concat(response.newTicket)); - } - - return getClientNonce(wsResult.originalTicket ? wsResult.originalTicket : response.newTicket, wsResult.ttl); - }).then(function () { - return result; - }); - }); - }; - - var toString = {}.toString; - - var isarray = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; - }; - - var K_MAX_LENGTH = 0x7fffffff; - - function Buffer (arg, offset, length) { - if (typeof arg === 'number') { - return allocUnsafe(arg) - } - - return from(arg, offset, length) - } - - Buffer.prototype.__proto__ = Uint8Array.prototype; - Buffer.__proto__ = Uint8Array; - - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true, - enumerable: false, - writable: false - }); - } - - function checked (length) { - // Note: cannot use `length < K_MAX_LENGTH` here because that fails when - // length is NaN (which is otherwise coerced to zero.) - if (length >= K_MAX_LENGTH) { - throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') - } - return length | 0 - } - - function isnan (val) { - return val !== val // eslint-disable-line no-self-compare - } - - function createBuffer (length) { - var buf = new Uint8Array(length); - buf.__proto__ = Buffer.prototype; - return buf - } - - function allocUnsafe (size) { - return createBuffer(size < 0 ? 0 : checked(size) | 0) - } - - function fromString (string) { - var length = byteLength(string) | 0; - var buf = createBuffer(length); - - var actual = buf.write(string); - - if (actual !== length) { - // Writing a hex string, for example, that contains invalid characters will - // cause everything after the first invalid character to be ignored. (e.g. - // 'abxxcd' will be treated as 'ab') - buf = buf.slice(0, actual); - } - - return buf - } - - function fromArrayLike (array) { - var length = array.length < 0 ? 0 : checked(array.length) | 0; - var buf = createBuffer(length); - for (var i = 0; i < length; i += 1) { - buf[i] = array[i] & 255; - } - return buf - } - - function fromArrayBuffer (array, byteOffset, length) { - if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') - } - - if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') - } - - var buf; - if (byteOffset === undefined && length === undefined) { - buf = new Uint8Array(array); - } else if (length === undefined) { - buf = new Uint8Array(array, byteOffset); - } else { - buf = new Uint8Array(array, byteOffset, length); - } - - // Return an augmented `Uint8Array` instance - buf.__proto__ = Buffer.prototype; - return buf - } - - function fromObject (obj) { - if (Buffer.isBuffer(obj)) { - var len = checked(obj.length) | 0; - var buf = createBuffer(len); - - if (buf.length === 0) { - return buf - } - - obj.copy(buf, 0, 0, len); - return buf - } - - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(0) - } - return fromArrayLike(obj) - } - - if (obj.type === 'Buffer' && Array.isArray(obj.data)) { - return fromArrayLike(obj.data) - } - } - - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') - } - - function utf8ToBytes (string, units) { - units = units || Infinity; - var codePoint; - var length = string.length; - var leadSurrogate = null; - var bytes = []; - - for (var i = 0; i < length; ++i) { - codePoint = string.charCodeAt(i); - - // is surrogate component - if (codePoint > 0xD7FF && codePoint < 0xE000) { - // last char was a lead - if (!leadSurrogate) { - // no lead yet - if (codePoint > 0xDBFF) { - // unexpected trail - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); - continue - } else if (i + 1 === length) { - // unpaired lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); - continue - } - - // valid lead - leadSurrogate = codePoint; - - continue - } - - // 2 leads in a row - if (codePoint < 0xDC00) { - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); - leadSurrogate = codePoint; - continue - } - - // valid surrogate pair - codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; - } else if (leadSurrogate) { - // valid bmp char, but last char was a lead - if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); - } - - leadSurrogate = null; - - // encode utf8 - if (codePoint < 0x80) { - if ((units -= 1) < 0) break - bytes.push(codePoint); - } else if (codePoint < 0x800) { - if ((units -= 2) < 0) break - bytes.push( - codePoint >> 0x6 | 0xC0, - codePoint & 0x3F | 0x80 - ); - } else if (codePoint < 0x10000) { - if ((units -= 3) < 0) break - bytes.push( - codePoint >> 0xC | 0xE0, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ); - } else if (codePoint < 0x110000) { - if ((units -= 4) < 0) break - bytes.push( - codePoint >> 0x12 | 0xF0, - codePoint >> 0xC & 0x3F | 0x80, - codePoint >> 0x6 & 0x3F | 0x80, - codePoint & 0x3F | 0x80 - ); - } else { - throw new Error('Invalid code point') - } - } - - return bytes - } - - function byteLength (string) { - if (Buffer.isBuffer(string)) { - return string.length - } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { - return string.byteLength - } - if (typeof string !== 'string') { - string = '' + string; - } - - var len = string.length; - if (len === 0) return 0 - - return utf8ToBytes(string).length - } - - function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; ++i) { - if ((i + offset >= dst.length) || (i >= src.length)) break - dst[i + offset] = src[i]; - } - return i - } - - function utf8Write (buf, string, offset, length) { - return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) - } - - function from (value, offset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(value, offset, length) - } - - if (typeof value === 'string') { - return fromString(value, offset) - } - - return fromObject(value) - } - - Buffer.prototype.write = function write (string, offset, length) { - // Buffer#write(string) - if (offset === undefined) { - length = this.length; - offset = 0; - // Buffer#write(string, encoding) - } else if (length === undefined && typeof offset === 'string') { - length = this.length; - offset = 0; - // Buffer#write(string, offset[, length]) - } else if (isFinite(offset)) { - offset = offset | 0; - if (isFinite(length)) { - length = length | 0; - } else { - length = undefined; - } - } - - var remaining = this.length - offset; - if (length === undefined || length > remaining) length = remaining; - - if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { - throw new RangeError('Attempt to write outside buffer bounds') - } - - return utf8Write(this, string, offset, length) - }; - - Buffer.prototype.slice = function slice (start, end) { - var len = this.length; - start = ~~start; - end = end === undefined ? len : ~~end; - - if (start < 0) { - start += len; - if (start < 0) start = 0; - } else if (start > len) { - start = len; - } - - if (end < 0) { - end += len; - if (end < 0) end = 0; - } else if (end > len) { - end = len; - } - - if (end < start) end = start; - - var newBuf = this.subarray(start, end); - // Return an augmented `Uint8Array` instance - newBuf.__proto__ = Buffer.prototype; - return newBuf - }; - - Buffer.prototype.copy = function copy (target, targetStart, start, end) { - if (!start) start = 0; - if (!end && end !== 0) end = this.length; - if (targetStart >= target.length) targetStart = target.length; - if (!targetStart) targetStart = 0; - if (end > 0 && end < start) end = start; - - // Copy 0 bytes; we're done - if (end === start) return 0 - if (target.length === 0 || this.length === 0) return 0 - - // Fatal error conditions - if (targetStart < 0) { - throw new RangeError('targetStart out of bounds') - } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') - if (end < 0) throw new RangeError('sourceEnd out of bounds') - - // Are we oob? - if (end > this.length) end = this.length; - if (target.length - targetStart < end - start) { - end = target.length - targetStart + start; - } - - var len = end - start; - var i; - - if (this === target && start < targetStart && targetStart < end) { - // descending copy from end - for (i = len - 1; i >= 0; --i) { - target[i + targetStart] = this[i + start]; - } - } else if (len < 1000) { - // ascending copy from start - for (i = 0; i < len; ++i) { - target[i + targetStart] = this[i + start]; - } - } else { - Uint8Array.prototype.set.call( - target, - this.subarray(start, start + len), - targetStart - ); - } - - return len - }; - - Buffer.prototype.fill = function fill (val, start, end) { - // Handle string cases: - if (typeof val === 'string') { - if (typeof start === 'string') { - start = 0; - end = this.length; - } else if (typeof end === 'string') { - end = this.length; - } - if (val.length === 1) { - var code = val.charCodeAt(0); - if (code < 256) { - val = code; - } - } - } else if (typeof val === 'number') { - val = val & 255; - } - - // Invalid ranges are not set to a default, so can range check early. - if (start < 0 || this.length < start || this.length < end) { - throw new RangeError('Out of range index') - } - - if (end <= start) { - return this - } - - start = start >>> 0; - end = end === undefined ? this.length : end >>> 0; - - if (!val) val = 0; - - var i; - if (typeof val === 'number') { - for (i = start; i < end; ++i) { - this[i] = val; - } - } else { - var bytes = Buffer.isBuffer(val) - ? val - : new Buffer(val); - var len = bytes.length; - for (i = 0; i < end - start; ++i) { - this[i + start] = bytes[i % len]; - } - } - - return this - }; - - Buffer.concat = function concat (list, length) { - if (!isarray(list)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - - if (list.length === 0) { - return createBuffer(null, 0) - } - - var i; - if (length === undefined) { - length = 0; - for (i = 0; i < list.length; ++i) { - length += list[i].length; - } - } - - var buffer = allocUnsafe(length); - var pos = 0; - for (i = 0; i < list.length; ++i) { - var buf = list[i]; - if (!Buffer.isBuffer(buf)) { - throw new TypeError('"list" argument must be an Array of Buffers') - } - buf.copy(buffer, pos); - pos += buf.length; - } - return buffer - }; - - Buffer.byteLength = byteLength; - - Buffer.prototype._isBuffer = true; - Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) - }; - - var typedarrayBuffer = Buffer; - - var toSJISFunction; - var CODEWORDS_COUNT = [ - 0, // Not used - 26, 44, 70, 100, 134, 172, 196, 242, 292, 346, - 404, 466, 532, 581, 655, 733, 815, 901, 991, 1085, - 1156, 1258, 1364, 1474, 1588, 1706, 1828, 1921, 2051, 2185, - 2323, 2465, 2611, 2761, 2876, 3034, 3196, 3362, 3532, 3706 - ]; - - /** - * Returns the QR Code size for the specified version - * - * @param {Number} version QR Code version - * @return {Number} size of QR code - */ - var getSymbolSize = function getSymbolSize (version) { - if (!version) throw new Error('"version" cannot be null or undefined') - if (version < 1 || version > 40) throw new Error('"version" should be in range from 1 to 40') - return version * 4 + 17 - }; - - /** - * Returns the total number of codewords used to store data and EC information. - * - * @param {Number} version QR Code version - * @return {Number} Data length in bits - */ - var getSymbolTotalCodewords = function getSymbolTotalCodewords (version) { - return CODEWORDS_COUNT[version] - }; - - /** - * Encode data with Bose-Chaudhuri-Hocquenghem - * - * @param {Number} data Value to encode - * @return {Number} Encoded value - */ - var getBCHDigit = function (data) { - var digit = 0; - - while (data !== 0) { - digit++; - data >>>= 1; - } - - return digit - }; - - var setToSJISFunction = function setToSJISFunction (f) { - if (typeof f !== 'function') { - throw new Error('"toSJISFunc" is not a valid function.') - } - - toSJISFunction = f; - }; - - var isKanjiModeEnabled = function () { - return typeof toSJISFunction !== 'undefined' - }; - - var toSJIS = function toSJIS (kanji) { - return toSJISFunction(kanji) - }; - - var utils = { - getSymbolSize: getSymbolSize, - getSymbolTotalCodewords: getSymbolTotalCodewords, - getBCHDigit: getBCHDigit, - setToSJISFunction: setToSJISFunction, - isKanjiModeEnabled: isKanjiModeEnabled, - toSJIS: toSJIS - }; - - var errorCorrectionLevel = createCommonjsModule(function (module, exports) { - exports.L = { bit: 1 }; - exports.M = { bit: 0 }; - exports.Q = { bit: 3 }; - exports.H = { bit: 2 }; - - function fromString (string) { - if (typeof string !== 'string') { - throw new Error('Param is not a string') - } - - var lcStr = string.toLowerCase(); - - switch (lcStr) { - case 'l': - case 'low': - return exports.L - - case 'm': - case 'medium': - return exports.M - - case 'q': - case 'quartile': - return exports.Q - - case 'h': - case 'high': - return exports.H - - default: - throw new Error('Unknown EC Level: ' + string) - } - } - - exports.isValid = function isValid (level) { - return level && typeof level.bit !== 'undefined' && - level.bit >= 0 && level.bit < 4 - }; - - exports.from = function from (value, defaultValue) { - if (exports.isValid(value)) { - return value - } - - try { - return fromString(value) - } catch (e) { - return defaultValue - } - }; - }); - var errorCorrectionLevel_1 = errorCorrectionLevel.L; - var errorCorrectionLevel_2 = errorCorrectionLevel.M; - var errorCorrectionLevel_3 = errorCorrectionLevel.Q; - var errorCorrectionLevel_4 = errorCorrectionLevel.H; - var errorCorrectionLevel_5 = errorCorrectionLevel.isValid; - - function BitBuffer () { - this.buffer = []; - this.length = 0; - } - - BitBuffer.prototype = { - - get: function (index) { - var bufIndex = Math.floor(index / 8); - return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) === 1 - }, - - put: function (num, length) { - for (var i = 0; i < length; i++) { - this.putBit(((num >>> (length - i - 1)) & 1) === 1); - } - }, - - getLengthInBits: function () { - return this.length - }, - - putBit: function (bit) { - var bufIndex = Math.floor(this.length / 8); - if (this.buffer.length <= bufIndex) { - this.buffer.push(0); - } - - if (bit) { - this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)); - } - - this.length++; - } - }; - - var bitBuffer = BitBuffer; - - /** - * Helper class to handle QR Code symbol modules - * - * @param {Number} size Symbol size - */ - function BitMatrix (size) { - if (!size || size < 1) { - throw new Error('BitMatrix size must be defined and greater than 0') - } - - this.size = size; - this.data = new typedarrayBuffer(size * size); - this.data.fill(0); - this.reservedBit = new typedarrayBuffer(size * size); - this.reservedBit.fill(0); - } - - /** - * Set bit value at specified location - * If reserved flag is set, this bit will be ignored during masking process - * - * @param {Number} row - * @param {Number} col - * @param {Boolean} value - * @param {Boolean} reserved - */ - BitMatrix.prototype.set = function (row, col, value, reserved) { - var index = row * this.size + col; - this.data[index] = value; - if (reserved) this.reservedBit[index] = true; - }; - - /** - * Returns bit value at specified location - * - * @param {Number} row - * @param {Number} col - * @return {Boolean} - */ - BitMatrix.prototype.get = function (row, col) { - return this.data[row * this.size + col] - }; - - /** - * Applies xor operator at specified location - * (used during masking process) - * - * @param {Number} row - * @param {Number} col - * @param {Boolean} value - */ - BitMatrix.prototype.xor = function (row, col, value) { - this.data[row * this.size + col] ^= value; - }; - - /** - * Check if bit at specified location is reserved - * - * @param {Number} row - * @param {Number} col - * @return {Boolean} - */ - BitMatrix.prototype.isReserved = function (row, col) { - return this.reservedBit[row * this.size + col] - }; - - var bitMatrix = BitMatrix; - - var alignmentPattern = createCommonjsModule(function (module, exports) { - /** - * Alignment pattern are fixed reference pattern in defined positions - * in a matrix symbology, which enables the decode software to re-synchronise - * the coordinate mapping of the image modules in the event of moderate amounts - * of distortion of the image. - * - * Alignment patterns are present only in QR Code symbols of version 2 or larger - * and their number depends on the symbol version. - */ - - var getSymbolSize = utils.getSymbolSize; - - /** - * Calculate the row/column coordinates of the center module of each alignment pattern - * for the specified QR Code version. - * - * The alignment patterns are positioned symmetrically on either side of the diagonal - * running from the top left corner of the symbol to the bottom right corner. - * - * Since positions are simmetrical only half of the coordinates are returned. - * Each item of the array will represent in turn the x and y coordinate. - * @see {@link getPositions} - * - * @param {Number} version QR Code version - * @return {Array} Array of coordinate - */ - exports.getRowColCoords = function getRowColCoords (version) { - if (version === 1) return [] - - var posCount = Math.floor(version / 7) + 2; - var size = getSymbolSize(version); - var intervals = size === 145 ? 26 : Math.ceil((size - 13) / (2 * posCount - 2)) * 2; - var positions = [size - 7]; // Last coord is always (size - 7) - - for (var i = 1; i < posCount - 1; i++) { - positions[i] = positions[i - 1] - intervals; - } - - positions.push(6); // First coord is always 6 - - return positions.reverse() - }; - - /** - * Returns an array containing the positions of each alignment pattern. - * Each array's element represent the center point of the pattern as (x, y) coordinates - * - * Coordinates are calculated expanding the row/column coordinates returned by {@link getRowColCoords} - * and filtering out the items that overlaps with finder pattern - * - * @example - * For a Version 7 symbol {@link getRowColCoords} returns values 6, 22 and 38. - * The alignment patterns, therefore, are to be centered on (row, column) - * positions (6,22), (22,6), (22,22), (22,38), (38,22), (38,38). - * Note that the coordinates (6,6), (6,38), (38,6) are occupied by finder patterns - * and are not therefore used for alignment patterns. - * - * var pos = getPositions(7) - * // [[6,22], [22,6], [22,22], [22,38], [38,22], [38,38]] - * - * @param {Number} version QR Code version - * @return {Array} Array of coordinates - */ - exports.getPositions = function getPositions (version) { - var coords = []; - var pos = exports.getRowColCoords(version); - var posLength = pos.length; - - for (var i = 0; i < posLength; i++) { - for (var j = 0; j < posLength; j++) { - // Skip if position is occupied by finder patterns - if ((i === 0 && j === 0) || // top-left - (i === 0 && j === posLength - 1) || // bottom-left - (i === posLength - 1 && j === 0)) { // top-right - continue - } - - coords.push([pos[i], pos[j]]); - } - } - - return coords - }; - }); - var alignmentPattern_1 = alignmentPattern.getRowColCoords; - var alignmentPattern_2 = alignmentPattern.getPositions; - - var getSymbolSize$1 = utils.getSymbolSize; - var FINDER_PATTERN_SIZE = 7; - - /** - * Returns an array containing the positions of each finder pattern. - * Each array's element represent the top-left point of the pattern as (x, y) coordinates - * - * @param {Number} version QR Code version - * @return {Array} Array of coordinates - */ - var getPositions = function getPositions (version) { - var size = getSymbolSize$1(version); - - return [ - // top-left - [0, 0], - // top-right - [size - FINDER_PATTERN_SIZE, 0], - // bottom-left - [0, size - FINDER_PATTERN_SIZE] - ] - }; - - var finderPattern = { - getPositions: getPositions - }; - - var maskPattern = createCommonjsModule(function (module, exports) { - /** - * Data mask pattern reference - * @type {Object} - */ - exports.Patterns = { - PATTERN000: 0, - PATTERN001: 1, - PATTERN010: 2, - PATTERN011: 3, - PATTERN100: 4, - PATTERN101: 5, - PATTERN110: 6, - PATTERN111: 7 - }; - - /** - * Weighted penalty scores for the undesirable features - * @type {Object} - */ - var PenaltyScores = { - N1: 3, - N2: 3, - N3: 40, - N4: 10 - }; - - /** - * Find adjacent modules in row/column with the same color - * and assign a penalty value. - * - * Points: N1 + i - * i is the amount by which the number of adjacent modules of the same color exceeds 5 - */ - exports.getPenaltyN1 = function getPenaltyN1 (data) { - var size = data.size; - var points = 0; - var sameCountCol = 0; - var sameCountRow = 0; - var lastCol = null; - var lastRow = null; - - for (var row = 0; row < size; row++) { - sameCountCol = sameCountRow = 0; - lastCol = lastRow = null; - - for (var col = 0; col < size; col++) { - var module = data.get(row, col); - if (module === lastCol) { - sameCountCol++; - } else { - if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5); - lastCol = module; - sameCountCol = 1; - } - - module = data.get(col, row); - if (module === lastRow) { - sameCountRow++; - } else { - if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5); - lastRow = module; - sameCountRow = 1; - } - } - - if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5); - if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5); - } - - return points - }; - - /** - * Find 2x2 blocks with the same color and assign a penalty value - * - * Points: N2 * (m - 1) * (n - 1) - */ - exports.getPenaltyN2 = function getPenaltyN2 (data) { - var size = data.size; - var points = 0; - - for (var row = 0; row < size - 1; row++) { - for (var col = 0; col < size - 1; col++) { - var last = data.get(row, col) + - data.get(row, col + 1) + - data.get(row + 1, col) + - data.get(row + 1, col + 1); - - if (last === 4 || last === 0) points++; - } - } - - return points * PenaltyScores.N2 - }; - - /** - * Find 1:1:3:1:1 ratio (dark:light:dark:light:dark) pattern in row/column, - * preceded or followed by light area 4 modules wide - * - * Points: N3 * number of pattern found - */ - exports.getPenaltyN3 = function getPenaltyN3 (data) { - var size = data.size; - var points = 0; - var bitsCol = 0; - var bitsRow = 0; - - for (var row = 0; row < size; row++) { - bitsCol = bitsRow = 0; - for (var col = 0; col < size; col++) { - bitsCol = ((bitsCol << 1) & 0x7FF) | data.get(row, col); - if (col >= 10 && (bitsCol === 0x5D0 || bitsCol === 0x05D)) points++; - - bitsRow = ((bitsRow << 1) & 0x7FF) | data.get(col, row); - if (col >= 10 && (bitsRow === 0x5D0 || bitsRow === 0x05D)) points++; - } - } - - return points * PenaltyScores.N3 - }; - - /** - * Calculate proportion of dark modules in entire symbol - * - * Points: N4 * k - * - * k is the rating of the deviation of the proportion of dark modules - * in the symbol from 50% in steps of 5% - */ - exports.getPenaltyN4 = function getPenaltyN4 (data) { - var darkCount = 0; - var modulesCount = data.data.length; - - for (var i = 0; i < modulesCount; i++) darkCount += data.data[i]; - - var k = Math.abs(Math.ceil((darkCount * 100 / modulesCount) / 5) - 10); - - return k * PenaltyScores.N4 - }; - - /** - * Return mask value at given position - * - * @param {Number} maskPattern Pattern reference value - * @param {Number} i Row - * @param {Number} j Column - * @return {Boolean} Mask value - */ - function getMaskAt (maskPattern, i, j) { - switch (maskPattern) { - case exports.Patterns.PATTERN000: return (i + j) % 2 === 0 - case exports.Patterns.PATTERN001: return i % 2 === 0 - case exports.Patterns.PATTERN010: return j % 3 === 0 - case exports.Patterns.PATTERN011: return (i + j) % 3 === 0 - case exports.Patterns.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0 - case exports.Patterns.PATTERN101: return (i * j) % 2 + (i * j) % 3 === 0 - case exports.Patterns.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 === 0 - case exports.Patterns.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 === 0 - - default: throw new Error('bad maskPattern:' + maskPattern) - } - } - - /** - * Apply a mask pattern to a BitMatrix - * - * @param {Number} pattern Pattern reference number - * @param {BitMatrix} data BitMatrix data - */ - exports.applyMask = function applyMask (pattern, data) { - var size = data.size; - - for (var col = 0; col < size; col++) { - for (var row = 0; row < size; row++) { - if (data.isReserved(row, col)) continue - data.xor(row, col, getMaskAt(pattern, row, col)); - } - } - }; - - /** - * Returns the best mask pattern for data - * - * @param {BitMatrix} data - * @return {Number} Mask pattern reference number - */ - exports.getBestMask = function getBestMask (data, setupFormatFunc) { - var numPatterns = Object.keys(exports.Patterns).length; - var bestPattern = 0; - var lowerPenalty = Infinity; - - for (var p = 0; p < numPatterns; p++) { - setupFormatFunc(p); - exports.applyMask(p, data); - - // Calculate penalty - var penalty = - exports.getPenaltyN1(data) + - exports.getPenaltyN2(data) + - exports.getPenaltyN3(data) + - exports.getPenaltyN4(data); - - // Undo previously applied mask - exports.applyMask(p, data); - - if (penalty < lowerPenalty) { - lowerPenalty = penalty; - bestPattern = p; - } - } - - return bestPattern - }; - }); - var maskPattern_1 = maskPattern.Patterns; - var maskPattern_2 = maskPattern.getPenaltyN1; - var maskPattern_3 = maskPattern.getPenaltyN2; - var maskPattern_4 = maskPattern.getPenaltyN3; - var maskPattern_5 = maskPattern.getPenaltyN4; - var maskPattern_6 = maskPattern.applyMask; - var maskPattern_7 = maskPattern.getBestMask; - - var EC_BLOCKS_TABLE = [ - // L M Q H - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 2, 2, - 1, 2, 2, 4, - 1, 2, 4, 4, - 2, 4, 4, 4, - 2, 4, 6, 5, - 2, 4, 6, 6, - 2, 5, 8, 8, - 4, 5, 8, 8, - 4, 5, 8, 11, - 4, 8, 10, 11, - 4, 9, 12, 16, - 4, 9, 16, 16, - 6, 10, 12, 18, - 6, 10, 17, 16, - 6, 11, 16, 19, - 6, 13, 18, 21, - 7, 14, 21, 25, - 8, 16, 20, 25, - 8, 17, 23, 25, - 9, 17, 23, 34, - 9, 18, 25, 30, - 10, 20, 27, 32, - 12, 21, 29, 35, - 12, 23, 34, 37, - 12, 25, 34, 40, - 13, 26, 35, 42, - 14, 28, 38, 45, - 15, 29, 40, 48, - 16, 31, 43, 51, - 17, 33, 45, 54, - 18, 35, 48, 57, - 19, 37, 51, 60, - 19, 38, 53, 63, - 20, 40, 56, 66, - 21, 43, 59, 70, - 22, 45, 62, 74, - 24, 47, 65, 77, - 25, 49, 68, 81 - ]; - - var EC_CODEWORDS_TABLE = [ - // L M Q H - 7, 10, 13, 17, - 10, 16, 22, 28, - 15, 26, 36, 44, - 20, 36, 52, 64, - 26, 48, 72, 88, - 36, 64, 96, 112, - 40, 72, 108, 130, - 48, 88, 132, 156, - 60, 110, 160, 192, - 72, 130, 192, 224, - 80, 150, 224, 264, - 96, 176, 260, 308, - 104, 198, 288, 352, - 120, 216, 320, 384, - 132, 240, 360, 432, - 144, 280, 408, 480, - 168, 308, 448, 532, - 180, 338, 504, 588, - 196, 364, 546, 650, - 224, 416, 600, 700, - 224, 442, 644, 750, - 252, 476, 690, 816, - 270, 504, 750, 900, - 300, 560, 810, 960, - 312, 588, 870, 1050, - 336, 644, 952, 1110, - 360, 700, 1020, 1200, - 390, 728, 1050, 1260, - 420, 784, 1140, 1350, - 450, 812, 1200, 1440, - 480, 868, 1290, 1530, - 510, 924, 1350, 1620, - 540, 980, 1440, 1710, - 570, 1036, 1530, 1800, - 570, 1064, 1590, 1890, - 600, 1120, 1680, 1980, - 630, 1204, 1770, 2100, - 660, 1260, 1860, 2220, - 720, 1316, 1950, 2310, - 750, 1372, 2040, 2430 - ]; - - /** - * Returns the number of error correction block that the QR Code should contain - * for the specified version and error correction level. - * - * @param {Number} version QR Code version - * @param {Number} errorCorrectionLevel Error correction level - * @return {Number} Number of error correction blocks - */ - var getBlocksCount = function getBlocksCount (version, errorCorrectionLevel$1) { - switch (errorCorrectionLevel$1) { - case errorCorrectionLevel.L: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 0] - case errorCorrectionLevel.M: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 1] - case errorCorrectionLevel.Q: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 2] - case errorCorrectionLevel.H: - return EC_BLOCKS_TABLE[(version - 1) * 4 + 3] - default: - return undefined - } - }; - - /** - * Returns the number of error correction codewords to use for the specified - * version and error correction level. - * - * @param {Number} version QR Code version - * @param {Number} errorCorrectionLevel Error correction level - * @return {Number} Number of error correction codewords - */ - var getTotalCodewordsCount = function getTotalCodewordsCount (version, errorCorrectionLevel$1) { - switch (errorCorrectionLevel$1) { - case errorCorrectionLevel.L: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 0] - case errorCorrectionLevel.M: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 1] - case errorCorrectionLevel.Q: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 2] - case errorCorrectionLevel.H: - return EC_CODEWORDS_TABLE[(version - 1) * 4 + 3] - default: - return undefined - } - }; - - var errorCorrectionCode = { - getBlocksCount: getBlocksCount, - getTotalCodewordsCount: getTotalCodewordsCount - }; - - var EXP_TABLE = new typedarrayBuffer(512); - var LOG_TABLE = new typedarrayBuffer(256) - - /** - * Precompute the log and anti-log tables for faster computation later - * - * For each possible value in the galois field 2^8, we will pre-compute - * the logarithm and anti-logarithm (exponential) of this value - * - * ref {@link https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#Introduction_to_mathematical_fields} - */ - ;(function initTables () { - var x = 1; - for (var i = 0; i < 255; i++) { - EXP_TABLE[i] = x; - LOG_TABLE[x] = i; - - x <<= 1; // multiply by 2 - - // The QR code specification says to use byte-wise modulo 100011101 arithmetic. - // This means that when a number is 256 or larger, it should be XORed with 0x11D. - if (x & 0x100) { // similar to x >= 256, but a lot faster (because 0x100 == 256) - x ^= 0x11D; - } - } - - // Optimization: double the size of the anti-log table so that we don't need to mod 255 to - // stay inside the bounds (because we will mainly use this table for the multiplication of - // two GF numbers, no more). - // @see {@link mul} - for (i = 255; i < 512; i++) { - EXP_TABLE[i] = EXP_TABLE[i - 255]; - } - }()); - - /** - * Returns log value of n inside Galois Field - * - * @param {Number} n - * @return {Number} - */ - var log = function log (n) { - if (n < 1) throw new Error('log(' + n + ')') - return LOG_TABLE[n] - }; - - /** - * Returns anti-log value of n inside Galois Field - * - * @param {Number} n - * @return {Number} - */ - var exp = function exp (n) { - return EXP_TABLE[n] - }; - - /** - * Multiplies two number inside Galois Field - * - * @param {Number} x - * @param {Number} y - * @return {Number} - */ - var mul = function mul (x, y) { - if (x === 0 || y === 0) return 0 - - // should be EXP_TABLE[(LOG_TABLE[x] + LOG_TABLE[y]) % 255] if EXP_TABLE wasn't oversized - // @see {@link initTables} - return EXP_TABLE[LOG_TABLE[x] + LOG_TABLE[y]] - }; - - var galoisField = { - log: log, - exp: exp, - mul: mul - }; - - var polynomial = createCommonjsModule(function (module, exports) { - /** - * Multiplies two polynomials inside Galois Field - * - * @param {Buffer} p1 Polynomial - * @param {Buffer} p2 Polynomial - * @return {Buffer} Product of p1 and p2 - */ - exports.mul = function mul (p1, p2) { - var coeff = new typedarrayBuffer(p1.length + p2.length - 1); - coeff.fill(0); - - for (var i = 0; i < p1.length; i++) { - for (var j = 0; j < p2.length; j++) { - coeff[i + j] ^= galoisField.mul(p1[i], p2[j]); - } - } - - return coeff - }; - - /** - * Calculate the remainder of polynomials division - * - * @param {Buffer} divident Polynomial - * @param {Buffer} divisor Polynomial - * @return {Buffer} Remainder - */ - exports.mod = function mod (divident, divisor) { - var result = new typedarrayBuffer(divident); - - while ((result.length - divisor.length) >= 0) { - var coeff = result[0]; - - for (var i = 0; i < divisor.length; i++) { - result[i] ^= galoisField.mul(divisor[i], coeff); - } - - // remove all zeros from buffer head - var offset = 0; - while (offset < result.length && result[offset] === 0) offset++; - result = result.slice(offset); - } - - return result - }; - - /** - * Generate an irreducible generator polynomial of specified degree - * (used by Reed-Solomon encoder) - * - * @param {Number} degree Degree of the generator polynomial - * @return {Buffer} Buffer containing polynomial coefficients - */ - exports.generateECPolynomial = function generateECPolynomial (degree) { - var poly = new typedarrayBuffer([1]); - for (var i = 0; i < degree; i++) { - poly = exports.mul(poly, [1, galoisField.exp(i)]); - } - - return poly - }; - }); - var polynomial_1 = polynomial.mul; - var polynomial_2 = polynomial.mod; - var polynomial_3 = polynomial.generateECPolynomial; - - function ReedSolomonEncoder (degree) { - this.genPoly = undefined; - this.degree = degree; - - if (this.degree) this.initialize(this.degree); - } - - /** - * Initialize the encoder. - * The input param should correspond to the number of error correction codewords. - * - * @param {Number} degree - */ - ReedSolomonEncoder.prototype.initialize = function initialize (degree) { - // create an irreducible generator polynomial - this.degree = degree; - this.genPoly = polynomial.generateECPolynomial(this.degree); - }; - - /** - * Encodes a chunk of data - * - * @param {Buffer} data Buffer containing input data - * @return {Buffer} Buffer containing encoded data - */ - ReedSolomonEncoder.prototype.encode = function encode (data) { - if (!this.genPoly) { - throw new Error('Encoder not initialized') - } - - // Calculate EC for this data block - // extends data size to data+genPoly size - var pad = new typedarrayBuffer(this.degree); - pad.fill(0); - var paddedData = typedarrayBuffer.concat([data, pad], data.length + this.degree); - - // The error correction codewords are the remainder after dividing the data codewords - // by a generator polynomial - var remainder = polynomial.mod(paddedData, this.genPoly); - - // return EC data blocks (last n byte, where n is the degree of genPoly) - // If coefficients number in remainder are less than genPoly degree, - // pad with 0s to the left to reach the needed number of coefficients - var start = this.degree - remainder.length; - if (start > 0) { - var buff = new typedarrayBuffer(this.degree); - buff.fill(0); - remainder.copy(buff, start); - - return buff - } - - return remainder - }; - - var reedSolomonEncoder = ReedSolomonEncoder; - - var numeric = '[0-9]+'; - var alphanumeric = '[A-Z $%*+-./:]+'; - var kanji = '(?:[\u3000-\u303F]|[\u3040-\u309F]|[\u30A0-\u30FF]|' + - '[\uFF00-\uFFEF]|[\u4E00-\u9FAF]|[\u2605-\u2606]|[\u2190-\u2195]|\u203B|' + - '[\u2010\u2015\u2018\u2019\u2025\u2026\u201C\u201D\u2225\u2260]|' + - '[\u0391-\u0451]|[\u00A7\u00A8\u00B1\u00B4\u00D7\u00F7])+'; - var byte = '(?:(?![A-Z0-9 $%*+-./:]|' + kanji + ').)+'; - - var KANJI = new RegExp(kanji, 'g'); - var BYTE_KANJI = new RegExp('[^A-Z0-9 $%*+-./:]+', 'g'); - var BYTE = new RegExp(byte, 'g'); - var NUMERIC = new RegExp(numeric, 'g'); - var ALPHANUMERIC = new RegExp(alphanumeric, 'g'); - - var TEST_KANJI = new RegExp('^' + kanji + '$'); - var TEST_NUMERIC = new RegExp('^' + numeric + '$'); - var TEST_ALPHANUMERIC = new RegExp('^[A-Z0-9 $%*+-./:]+$'); - - var testKanji = function testKanji (str) { - return TEST_KANJI.test(str) - }; - - var testNumeric = function testNumeric (str) { - return TEST_NUMERIC.test(str) - }; - - var testAlphanumeric = function testAlphanumeric (str) { - return TEST_ALPHANUMERIC.test(str) - }; - - var regex = { - KANJI: KANJI, - BYTE_KANJI: BYTE_KANJI, - BYTE: BYTE, - NUMERIC: NUMERIC, - ALPHANUMERIC: ALPHANUMERIC, - testKanji: testKanji, - testNumeric: testNumeric, - testAlphanumeric: testAlphanumeric - }; - - var mode = createCommonjsModule(function (module, exports) { - /** - * Numeric mode encodes data from the decimal digit set (0 - 9) - * (byte values 30HEX to 39HEX). - * Normally, 3 data characters are represented by 10 bits. - * - * @type {Object} - */ - exports.NUMERIC = { - id: 'Numeric', - bit: 1 << 0, - ccBits: [10, 12, 14] - }; - - /** - * Alphanumeric mode encodes data from a set of 45 characters, - * i.e. 10 numeric digits (0 - 9), - * 26 alphabetic characters (A - Z), - * and 9 symbols (SP, $, %, *, +, -, ., /, :). - * Normally, two input characters are represented by 11 bits. - * - * @type {Object} - */ - exports.ALPHANUMERIC = { - id: 'Alphanumeric', - bit: 1 << 1, - ccBits: [9, 11, 13] - }; - - /** - * In byte mode, data is encoded at 8 bits per character. - * - * @type {Object} - */ - exports.BYTE = { - id: 'Byte', - bit: 1 << 2, - ccBits: [8, 16, 16] - }; - - /** - * The Kanji mode efficiently encodes Kanji characters in accordance with - * the Shift JIS system based on JIS X 0208. - * The Shift JIS values are shifted from the JIS X 0208 values. - * JIS X 0208 gives details of the shift coded representation. - * Each two-byte character value is compacted to a 13-bit binary codeword. - * - * @type {Object} - */ - exports.KANJI = { - id: 'Kanji', - bit: 1 << 3, - ccBits: [8, 10, 12] - }; - - /** - * Mixed mode will contain a sequences of data in a combination of any of - * the modes described above - * - * @type {Object} - */ - exports.MIXED = { - bit: -1 - }; - - /** - * Returns the number of bits needed to store the data length - * according to QR Code specifications. - * - * @param {Mode} mode Data mode - * @param {Number} version QR Code version - * @return {Number} Number of bits - */ - exports.getCharCountIndicator = function getCharCountIndicator (mode, version$1) { - if (!mode.ccBits) throw new Error('Invalid mode: ' + mode) - - if (!version.isValid(version$1)) { - throw new Error('Invalid version: ' + version$1) - } - - if (version$1 >= 1 && version$1 < 10) return mode.ccBits[0] - else if (version$1 < 27) return mode.ccBits[1] - return mode.ccBits[2] - }; - - /** - * Returns the most efficient mode to store the specified data - * - * @param {String} dataStr Input data string - * @return {Mode} Best mode - */ - exports.getBestModeForData = function getBestModeForData (dataStr) { - if (regex.testNumeric(dataStr)) return exports.NUMERIC - else if (regex.testAlphanumeric(dataStr)) return exports.ALPHANUMERIC - else if (regex.testKanji(dataStr)) return exports.KANJI - else return exports.BYTE - }; - - /** - * Return mode name as string - * - * @param {Mode} mode Mode object - * @returns {String} Mode name - */ - exports.toString = function toString (mode) { - if (mode && mode.id) return mode.id - throw new Error('Invalid mode') - }; - - /** - * Check if input param is a valid mode object - * - * @param {Mode} mode Mode object - * @returns {Boolean} True if valid mode, false otherwise - */ - exports.isValid = function isValid (mode) { - return mode && mode.bit && mode.ccBits - }; - - /** - * Get mode object from its name - * - * @param {String} string Mode name - * @returns {Mode} Mode object - */ - function fromString (string) { - if (typeof string !== 'string') { - throw new Error('Param is not a string') - } - - var lcStr = string.toLowerCase(); - - switch (lcStr) { - case 'numeric': - return exports.NUMERIC - case 'alphanumeric': - return exports.ALPHANUMERIC - case 'kanji': - return exports.KANJI - case 'byte': - return exports.BYTE - default: - throw new Error('Unknown mode: ' + string) - } - } - - /** - * Returns mode from a value. - * If value is not a valid mode, returns defaultValue - * - * @param {Mode|String} value Encoding mode - * @param {Mode} defaultValue Fallback value - * @return {Mode} Encoding mode - */ - exports.from = function from (value, defaultValue) { - if (exports.isValid(value)) { - return value - } - - try { - return fromString(value) - } catch (e) { - return defaultValue - } - }; - }); - var mode_1 = mode.NUMERIC; - var mode_2 = mode.ALPHANUMERIC; - var mode_3 = mode.BYTE; - var mode_4 = mode.KANJI; - var mode_5 = mode.MIXED; - var mode_6 = mode.getCharCountIndicator; - var mode_7 = mode.getBestModeForData; - var mode_8 = mode.isValid; - - var version = createCommonjsModule(function (module, exports) { - // Generator polynomial used to encode version information - var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); - var G18_BCH = utils.getBCHDigit(G18); - - function getBestVersionForDataLength (mode, length, errorCorrectionLevel) { - for (var currentVersion = 1; currentVersion <= 40; currentVersion++) { - if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, mode)) { - return currentVersion - } - } - - return undefined - } - - function getReservedBitsCount (mode$1, version) { - // Character count indicator + mode indicator bits - return mode.getCharCountIndicator(mode$1, version) + 4 - } - - function getTotalBitsFromDataArray (segments, version) { - var totalBits = 0; - - segments.forEach(function (data) { - var reservedBits = getReservedBitsCount(data.mode, version); - totalBits += reservedBits + data.getBitsLength(); - }); - - return totalBits - } - - function getBestVersionForMixedData (segments, errorCorrectionLevel) { - for (var currentVersion = 1; currentVersion <= 40; currentVersion++) { - var length = getTotalBitsFromDataArray(segments, currentVersion); - if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, mode.MIXED)) { - return currentVersion - } - } - - return undefined - } - - /** - * Check if QR Code version is valid - * - * @param {Number} version QR Code version - * @return {Boolean} true if valid version, false otherwise - */ - exports.isValid = function isValid (version) { - return !isNaN(version) && version >= 1 && version <= 40 - }; - - /** - * Returns version number from a value. - * If value is not a valid version, returns defaultValue - * - * @param {Number|String} value QR Code version - * @param {Number} defaultValue Fallback value - * @return {Number} QR Code version number - */ - exports.from = function from (value, defaultValue) { - if (exports.isValid(value)) { - return parseInt(value, 10) - } - - return defaultValue - }; - - /** - * Returns how much data can be stored with the specified QR code version - * and error correction level - * - * @param {Number} version QR Code version (1-40) - * @param {Number} errorCorrectionLevel Error correction level - * @param {Mode} mode Data mode - * @return {Number} Quantity of storable data - */ - exports.getCapacity = function getCapacity (version, errorCorrectionLevel, mode$1) { - if (!exports.isValid(version)) { - throw new Error('Invalid QR Code version') - } - - // Use Byte mode as default - if (typeof mode$1 === 'undefined') mode$1 = mode.BYTE; - - // Total codewords for this QR code version (Data + Error correction) - var totalCodewords = utils.getSymbolTotalCodewords(version); - - // Total number of error correction codewords - var ecTotalCodewords = errorCorrectionCode.getTotalCodewordsCount(version, errorCorrectionLevel); - - // Total number of data codewords - var dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8; - - if (mode$1 === mode.MIXED) return dataTotalCodewordsBits - - var usableBits = dataTotalCodewordsBits - getReservedBitsCount(mode$1, version); - - // Return max number of storable codewords - switch (mode$1) { - case mode.NUMERIC: - return Math.floor((usableBits / 10) * 3) - - case mode.ALPHANUMERIC: - return Math.floor((usableBits / 11) * 2) - - case mode.KANJI: - return Math.floor(usableBits / 13) - - case mode.BYTE: - default: - return Math.floor(usableBits / 8) - } - }; - - /** - * Returns the minimum version needed to contain the amount of data - * - * @param {Segment} data Segment of data - * @param {Number} [errorCorrectionLevel=H] Error correction level - * @param {Mode} mode Data mode - * @return {Number} QR Code version - */ - exports.getBestVersionForData = function getBestVersionForData (data, errorCorrectionLevel$1) { - var seg; - - var ecl = errorCorrectionLevel.from(errorCorrectionLevel$1, errorCorrectionLevel.M); - - if (isarray(data)) { - if (data.length > 1) { - return getBestVersionForMixedData(data, ecl) - } - - if (data.length === 0) { - return 1 - } - - seg = data[0]; - } else { - seg = data; - } - - return getBestVersionForDataLength(seg.mode, seg.getLength(), ecl) - }; - - /** - * Returns version information with relative error correction bits - * - * The version information is included in QR Code symbols of version 7 or larger. - * It consists of an 18-bit sequence containing 6 data bits, - * with 12 error correction bits calculated using the (18, 6) Golay code. - * - * @param {Number} version QR Code version - * @return {Number} Encoded version info bits - */ - exports.getEncodedBits = function getEncodedBits (version) { - if (!exports.isValid(version) || version < 7) { - throw new Error('Invalid QR Code version') - } - - var d = version << 12; - - while (utils.getBCHDigit(d) - G18_BCH >= 0) { - d ^= (G18 << (utils.getBCHDigit(d) - G18_BCH)); - } - - return (version << 12) | d - }; - }); - var version_1 = version.isValid; - var version_2 = version.getCapacity; - var version_3 = version.getBestVersionForData; - var version_4 = version.getEncodedBits; - - var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); - var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); - var G15_BCH = utils.getBCHDigit(G15); - - /** - * Returns format information with relative error correction bits - * - * The format information is a 15-bit sequence containing 5 data bits, - * with 10 error correction bits calculated using the (15, 5) BCH code. - * - * @param {Number} errorCorrectionLevel Error correction level - * @param {Number} mask Mask pattern - * @return {Number} Encoded format information bits - */ - var getEncodedBits = function getEncodedBits (errorCorrectionLevel, mask) { - var data = ((errorCorrectionLevel.bit << 3) | mask); - var d = data << 10; - - while (utils.getBCHDigit(d) - G15_BCH >= 0) { - d ^= (G15 << (utils.getBCHDigit(d) - G15_BCH)); - } - - // xor final data with mask pattern in order to ensure that - // no combination of Error Correction Level and data mask pattern - // will result in an all-zero data string - return ((data << 10) | d) ^ G15_MASK - }; - - var formatInfo = { - getEncodedBits: getEncodedBits - }; - - function NumericData (data) { - this.mode = mode.NUMERIC; - this.data = data.toString(); - } - - NumericData.getBitsLength = function getBitsLength (length) { - return 10 * Math.floor(length / 3) + ((length % 3) ? ((length % 3) * 3 + 1) : 0) - }; - - NumericData.prototype.getLength = function getLength () { - return this.data.length - }; - - NumericData.prototype.getBitsLength = function getBitsLength () { - return NumericData.getBitsLength(this.data.length) - }; - - NumericData.prototype.write = function write (bitBuffer) { - var i, group, value; - - // The input data string is divided into groups of three digits, - // and each group is converted to its 10-bit binary equivalent. - for (i = 0; i + 3 <= this.data.length; i += 3) { - group = this.data.substr(i, 3); - value = parseInt(group, 10); - - bitBuffer.put(value, 10); - } - - // If the number of input digits is not an exact multiple of three, - // the final one or two digits are converted to 4 or 7 bits respectively. - var remainingNum = this.data.length - i; - if (remainingNum > 0) { - group = this.data.substr(i); - value = parseInt(group, 10); - - bitBuffer.put(value, remainingNum * 3 + 1); - } - }; - - var numericData = NumericData; - - /** - * Array of characters available in alphanumeric mode - * - * As per QR Code specification, to each character - * is assigned a value from 0 to 44 which in this case coincides - * with the array index - * - * @type {Array} - */ - var ALPHA_NUM_CHARS = [ - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - ' ', '$', '%', '*', '+', '-', '.', '/', ':' - ]; - - function AlphanumericData (data) { - this.mode = mode.ALPHANUMERIC; - this.data = data; - } - - AlphanumericData.getBitsLength = function getBitsLength (length) { - return 11 * Math.floor(length / 2) + 6 * (length % 2) - }; - - AlphanumericData.prototype.getLength = function getLength () { - return this.data.length - }; - - AlphanumericData.prototype.getBitsLength = function getBitsLength () { - return AlphanumericData.getBitsLength(this.data.length) - }; - - AlphanumericData.prototype.write = function write (bitBuffer) { - var i; - - // Input data characters are divided into groups of two characters - // and encoded as 11-bit binary codes. - for (i = 0; i + 2 <= this.data.length; i += 2) { - // The character value of the first character is multiplied by 45 - var value = ALPHA_NUM_CHARS.indexOf(this.data[i]) * 45; - - // The character value of the second digit is added to the product - value += ALPHA_NUM_CHARS.indexOf(this.data[i + 1]); - - // The sum is then stored as 11-bit binary number - bitBuffer.put(value, 11); - } - - // If the number of input data characters is not a multiple of two, - // the character value of the final character is encoded as a 6-bit binary number. - if (this.data.length % 2) { - bitBuffer.put(ALPHA_NUM_CHARS.indexOf(this.data[i]), 6); - } - }; - - var alphanumericData = AlphanumericData; - - function ByteData (data) { - this.mode = mode.BYTE; - this.data = new typedarrayBuffer(data); - } - - ByteData.getBitsLength = function getBitsLength (length) { - return length * 8 - }; - - ByteData.prototype.getLength = function getLength () { - return this.data.length - }; - - ByteData.prototype.getBitsLength = function getBitsLength () { - return ByteData.getBitsLength(this.data.length) - }; - - ByteData.prototype.write = function (bitBuffer) { - for (var i = 0, l = this.data.length; i < l; i++) { - bitBuffer.put(this.data[i], 8); - } - }; - - var byteData = ByteData; - - function KanjiData (data) { - this.mode = mode.KANJI; - this.data = data; - } - - KanjiData.getBitsLength = function getBitsLength (length) { - return length * 13 - }; - - KanjiData.prototype.getLength = function getLength () { - return this.data.length - }; - - KanjiData.prototype.getBitsLength = function getBitsLength () { - return KanjiData.getBitsLength(this.data.length) - }; - - KanjiData.prototype.write = function (bitBuffer) { - var i; - - // In the Shift JIS system, Kanji characters are represented by a two byte combination. - // These byte values are shifted from the JIS X 0208 values. - // JIS X 0208 gives details of the shift coded representation. - for (i = 0; i < this.data.length; i++) { - var value = utils.toSJIS(this.data[i]); - - // For characters with Shift JIS values from 0x8140 to 0x9FFC: - if (value >= 0x8140 && value <= 0x9FFC) { - // Subtract 0x8140 from Shift JIS value - value -= 0x8140; - - // For characters with Shift JIS values from 0xE040 to 0xEBBF - } else if (value >= 0xE040 && value <= 0xEBBF) { - // Subtract 0xC140 from Shift JIS value - value -= 0xC140; - } else { - throw new Error( - 'Invalid SJIS character: ' + this.data[i] + '\n' + - 'Make sure your charset is UTF-8') - } - - // Multiply most significant byte of result by 0xC0 - // and add least significant byte to product - value = (((value >>> 8) & 0xff) * 0xC0) + (value & 0xff); - - // Convert result to a 13-bit binary string - bitBuffer.put(value, 13); - } - }; - - var kanjiData = KanjiData; - - var dijkstra_1 = createCommonjsModule(function (module) { - - /****************************************************************************** - * Created 2008-08-19. - * - * Dijkstra path-finding functions. Adapted from the Dijkstar Python project. - * - * Copyright (C) 2008 - * Wyatt Baldwin - * All rights reserved - * - * Licensed under the MIT license. - * - * http://www.opensource.org/licenses/mit-license.php - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - *****************************************************************************/ - var dijkstra = { - single_source_shortest_paths: function(graph, s, d) { - // Predecessor map for each node that has been encountered. - // node ID => predecessor node ID - var predecessors = {}; - - // Costs of shortest paths from s to all nodes encountered. - // node ID => cost - var costs = {}; - costs[s] = 0; - - // Costs of shortest paths from s to all nodes encountered; differs from - // `costs` in that it provides easy access to the node that currently has - // the known shortest path from s. - // XXX: Do we actually need both `costs` and `open`? - var open = dijkstra.PriorityQueue.make(); - open.push(s, 0); - - var closest, - u, v, - cost_of_s_to_u, - adjacent_nodes, - cost_of_e, - cost_of_s_to_u_plus_cost_of_e, - cost_of_s_to_v, - first_visit; - while (!open.empty()) { - // In the nodes remaining in graph that have a known cost from s, - // find the node, u, that currently has the shortest path from s. - closest = open.pop(); - u = closest.value; - cost_of_s_to_u = closest.cost; - - // Get nodes adjacent to u... - adjacent_nodes = graph[u] || {}; - - // ...and explore the edges that connect u to those nodes, updating - // the cost of the shortest paths to any or all of those nodes as - // necessary. v is the node across the current edge from u. - for (v in adjacent_nodes) { - if (adjacent_nodes.hasOwnProperty(v)) { - // Get the cost of the edge running from u to v. - cost_of_e = adjacent_nodes[v]; - - // Cost of s to u plus the cost of u to v across e--this is *a* - // cost from s to v that may or may not be less than the current - // known cost to v. - cost_of_s_to_u_plus_cost_of_e = cost_of_s_to_u + cost_of_e; - - // If we haven't visited v yet OR if the current known cost from s to - // v is greater than the new cost we just found (cost of s to u plus - // cost of u to v across e), update v's cost in the cost list and - // update v's predecessor in the predecessor list (it's now u). - cost_of_s_to_v = costs[v]; - first_visit = (typeof costs[v] === 'undefined'); - if (first_visit || cost_of_s_to_v > cost_of_s_to_u_plus_cost_of_e) { - costs[v] = cost_of_s_to_u_plus_cost_of_e; - open.push(v, cost_of_s_to_u_plus_cost_of_e); - predecessors[v] = u; - } - } - } - } - - if (typeof d !== 'undefined' && typeof costs[d] === 'undefined') { - var msg = ['Could not find a path from ', s, ' to ', d, '.'].join(''); - throw new Error(msg); - } - - return predecessors; - }, - - extract_shortest_path_from_predecessor_list: function(predecessors, d) { - var nodes = []; - var u = d; - var predecessor; - while (u) { - nodes.push(u); - predecessor = predecessors[u]; - u = predecessors[u]; - } - nodes.reverse(); - return nodes; - }, - - find_path: function(graph, s, d) { - var predecessors = dijkstra.single_source_shortest_paths(graph, s, d); - return dijkstra.extract_shortest_path_from_predecessor_list( - predecessors, d); - }, - - /** - * A very naive priority queue implementation. - */ - PriorityQueue: { - make: function (opts) { - var T = dijkstra.PriorityQueue, - t = {}, - key; - opts = opts || {}; - for (key in T) { - if (T.hasOwnProperty(key)) { - t[key] = T[key]; - } - } - t.queue = []; - t.sorter = opts.sorter || T.default_sorter; - return t; - }, - - default_sorter: function (a, b) { - return a.cost - b.cost; - }, - - /** - * Add a new item to the queue and ensure the highest priority element - * is at the front of the queue. - */ - push: function (value, cost) { - var item = {value: value, cost: cost}; - this.queue.push(item); - this.queue.sort(this.sorter); - }, - - /** - * Return the highest priority element in the queue. - */ - pop: function () { - return this.queue.shift(); - }, - - empty: function () { - return this.queue.length === 0; - } - } - }; - - - // node.js module exports - { - module.exports = dijkstra; - } - }); - - var segments = createCommonjsModule(function (module, exports) { - /** - * Returns UTF8 byte length - * - * @param {String} str Input string - * @return {Number} Number of byte - */ - function getStringByteLength (str) { - return unescape(encodeURIComponent(str)).length - } - - /** - * Get a list of segments of the specified mode - * from a string - * - * @param {Mode} mode Segment mode - * @param {String} str String to process - * @return {Array} Array of object with segments data - */ - function getSegments (regex, mode, str) { - var segments = []; - var result; - - while ((result = regex.exec(str)) !== null) { - segments.push({ - data: result[0], - index: result.index, - mode: mode, - length: result[0].length - }); - } - - return segments - } - - /** - * Extracts a series of segments with the appropriate - * modes from a string - * - * @param {String} dataStr Input string - * @return {Array} Array of object with segments data - */ - function getSegmentsFromString (dataStr) { - var numSegs = getSegments(regex.NUMERIC, mode.NUMERIC, dataStr); - var alphaNumSegs = getSegments(regex.ALPHANUMERIC, mode.ALPHANUMERIC, dataStr); - var byteSegs; - var kanjiSegs; - - if (utils.isKanjiModeEnabled()) { - byteSegs = getSegments(regex.BYTE, mode.BYTE, dataStr); - kanjiSegs = getSegments(regex.KANJI, mode.KANJI, dataStr); - } else { - byteSegs = getSegments(regex.BYTE_KANJI, mode.BYTE, dataStr); - kanjiSegs = []; - } - - var segs = numSegs.concat(alphaNumSegs, byteSegs, kanjiSegs); - - return segs - .sort(function (s1, s2) { - return s1.index - s2.index - }) - .map(function (obj) { - return { - data: obj.data, - mode: obj.mode, - length: obj.length - } - }) - } - - /** - * Returns how many bits are needed to encode a string of - * specified length with the specified mode - * - * @param {Number} length String length - * @param {Mode} mode Segment mode - * @return {Number} Bit length - */ - function getSegmentBitsLength (length, mode$1) { - switch (mode$1) { - case mode.NUMERIC: - return numericData.getBitsLength(length) - case mode.ALPHANUMERIC: - return alphanumericData.getBitsLength(length) - case mode.KANJI: - return kanjiData.getBitsLength(length) - case mode.BYTE: - return byteData.getBitsLength(length) - } - } - - /** - * Merges adjacent segments which have the same mode - * - * @param {Array} segs Array of object with segments data - * @return {Array} Array of object with segments data - */ - function mergeSegments (segs) { - return segs.reduce(function (acc, curr) { - var prevSeg = acc.length - 1 >= 0 ? acc[acc.length - 1] : null; - if (prevSeg && prevSeg.mode === curr.mode) { - acc[acc.length - 1].data += curr.data; - return acc - } - - acc.push(curr); - return acc - }, []) - } - - /** - * Generates a list of all possible nodes combination which - * will be used to build a segments graph. - * - * Nodes are divided by groups. Each group will contain a list of all the modes - * in which is possible to encode the given text. - * - * For example the text '12345' can be encoded as Numeric, Alphanumeric or Byte. - * The group for '12345' will contain then 3 objects, one for each - * possible encoding mode. - * - * Each node represents a possible segment. - * - * @param {Array} segs Array of object with segments data - * @return {Array} Array of object with segments data - */ - function buildNodes (segs) { - var nodes = []; - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - - switch (seg.mode) { - case mode.NUMERIC: - nodes.push([seg, - { data: seg.data, mode: mode.ALPHANUMERIC, length: seg.length }, - { data: seg.data, mode: mode.BYTE, length: seg.length } - ]); - break - case mode.ALPHANUMERIC: - nodes.push([seg, - { data: seg.data, mode: mode.BYTE, length: seg.length } - ]); - break - case mode.KANJI: - nodes.push([seg, - { data: seg.data, mode: mode.BYTE, length: getStringByteLength(seg.data) } - ]); - break - case mode.BYTE: - nodes.push([ - { data: seg.data, mode: mode.BYTE, length: getStringByteLength(seg.data) } - ]); - } - } - - return nodes - } - - /** - * Builds a graph from a list of nodes. - * All segments in each node group will be connected with all the segments of - * the next group and so on. - * - * At each connection will be assigned a weight depending on the - * segment's byte length. - * - * @param {Array} nodes Array of object with segments data - * @param {Number} version QR Code version - * @return {Object} Graph of all possible segments - */ - function buildGraph (nodes, version) { - var table = {}; - var graph = {'start': {}}; - var prevNodeIds = ['start']; - - for (var i = 0; i < nodes.length; i++) { - var nodeGroup = nodes[i]; - var currentNodeIds = []; - - for (var j = 0; j < nodeGroup.length; j++) { - var node = nodeGroup[j]; - var key = '' + i + j; - - currentNodeIds.push(key); - table[key] = { node: node, lastCount: 0 }; - graph[key] = {}; - - for (var n = 0; n < prevNodeIds.length; n++) { - var prevNodeId = prevNodeIds[n]; - - if (table[prevNodeId] && table[prevNodeId].node.mode === node.mode) { - graph[prevNodeId][key] = - getSegmentBitsLength(table[prevNodeId].lastCount + node.length, node.mode) - - getSegmentBitsLength(table[prevNodeId].lastCount, node.mode); - - table[prevNodeId].lastCount += node.length; - } else { - if (table[prevNodeId]) table[prevNodeId].lastCount = node.length; - - graph[prevNodeId][key] = getSegmentBitsLength(node.length, node.mode) + - 4 + mode.getCharCountIndicator(node.mode, version); // switch cost - } - } - } - - prevNodeIds = currentNodeIds; - } - - for (n = 0; n < prevNodeIds.length; n++) { - graph[prevNodeIds[n]]['end'] = 0; - } - - return { map: graph, table: table } - } - - /** - * Builds a segment from a specified data and mode. - * If a mode is not specified, the more suitable will be used. - * - * @param {String} data Input data - * @param {Mode | String} modesHint Data mode - * @return {Segment} Segment - */ - function buildSingleSegment (data, modesHint) { - var mode$1; - var bestMode = mode.getBestModeForData(data); - - mode$1 = mode.from(modesHint, bestMode); - - // Make sure data can be encoded - if (mode$1 !== mode.BYTE && mode$1.bit < bestMode.bit) { - throw new Error('"' + data + '"' + - ' cannot be encoded with mode ' + mode.toString(mode$1) + - '.\n Suggested mode is: ' + mode.toString(bestMode)) - } - - // Use Mode.BYTE if Kanji support is disabled - if (mode$1 === mode.KANJI && !utils.isKanjiModeEnabled()) { - mode$1 = mode.BYTE; - } - - switch (mode$1) { - case mode.NUMERIC: - return new numericData(data) - - case mode.ALPHANUMERIC: - return new alphanumericData(data) - - case mode.KANJI: - return new kanjiData(data) - - case mode.BYTE: - return new byteData(data) - } - } - - /** - * Builds a list of segments from an array. - * Array can contain Strings or Objects with segment's info. - * - * For each item which is a string, will be generated a segment with the given - * string and the more appropriate encoding mode. - * - * For each item which is an object, will be generated a segment with the given - * data and mode. - * Objects must contain at least the property "data". - * If property "mode" is not present, the more suitable mode will be used. - * - * @param {Array} array Array of objects with segments data - * @return {Array} Array of Segments - */ - exports.fromArray = function fromArray (array) { - return array.reduce(function (acc, seg) { - if (typeof seg === 'string') { - acc.push(buildSingleSegment(seg, null)); - } else if (seg.data) { - acc.push(buildSingleSegment(seg.data, seg.mode)); - } - - return acc - }, []) - }; - - /** - * Builds an optimized sequence of segments from a string, - * which will produce the shortest possible bitstream. - * - * @param {String} data Input string - * @param {Number} version QR Code version - * @return {Array} Array of segments - */ - exports.fromString = function fromString (data, version) { - var segs = getSegmentsFromString(data, utils.isKanjiModeEnabled()); - - var nodes = buildNodes(segs); - var graph = buildGraph(nodes, version); - var path = dijkstra_1.find_path(graph.map, 'start', 'end'); - - var optimizedSegs = []; - for (var i = 1; i < path.length - 1; i++) { - optimizedSegs.push(graph.table[path[i]].node); - } - - return exports.fromArray(mergeSegments(optimizedSegs)) - }; - - /** - * Splits a string in various segments with the modes which - * best represent their content. - * The produced segments are far from being optimized. - * The output of this function is only used to estimate a QR Code version - * which may contain the data. - * - * @param {string} data Input string - * @return {Array} Array of segments - */ - exports.rawSplit = function rawSplit (data) { - return exports.fromArray( - getSegmentsFromString(data, utils.isKanjiModeEnabled()) - ) - }; - }); - var segments_1 = segments.fromArray; - var segments_2 = segments.fromString; - var segments_3 = segments.rawSplit; - - /** - * QRCode for JavaScript - * - * modified by Ryan Day for nodejs support - * Copyright (c) 2011 Ryan Day - * - * Licensed under the MIT license: - * http://www.opensource.org/licenses/mit-license.php - * - //--------------------------------------------------------------------- - // QRCode for JavaScript - // - // Copyright (c) 2009 Kazuhiko Arase - // - // URL: http://www.d-project.com/ - // - // Licensed under the MIT license: - // http://www.opensource.org/licenses/mit-license.php - // - // The word "QR Code" is registered trademark of - // DENSO WAVE INCORPORATED - // http://www.denso-wave.com/qrcode/faqpatent-e.html - // - //--------------------------------------------------------------------- - */ - - /** - * Add finder patterns bits to matrix - * - * @param {BitMatrix} matrix Modules matrix - * @param {Number} version QR Code version - */ - function setupFinderPattern (matrix, version) { - var size = matrix.size; - var pos = finderPattern.getPositions(version); - - for (var i = 0; i < pos.length; i++) { - var row = pos[i][0]; - var col = pos[i][1]; - - for (var r = -1; r <= 7; r++) { - if (row + r <= -1 || size <= row + r) continue - - for (var c = -1; c <= 7; c++) { - if (col + c <= -1 || size <= col + c) continue - - if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) || - (c >= 0 && c <= 6 && (r === 0 || r === 6)) || - (r >= 2 && r <= 4 && c >= 2 && c <= 4)) { - matrix.set(row + r, col + c, true, true); - } else { - matrix.set(row + r, col + c, false, true); - } - } - } - } - } - - /** - * Add timing pattern bits to matrix - * - * Note: this function must be called before {@link setupAlignmentPattern} - * - * @param {BitMatrix} matrix Modules matrix - */ - function setupTimingPattern (matrix) { - var size = matrix.size; - - for (var r = 8; r < size - 8; r++) { - var value = r % 2 === 0; - matrix.set(r, 6, value, true); - matrix.set(6, r, value, true); - } - } - - /** - * Add alignment patterns bits to matrix - * - * Note: this function must be called after {@link setupTimingPattern} - * - * @param {BitMatrix} matrix Modules matrix - * @param {Number} version QR Code version - */ - function setupAlignmentPattern (matrix, version) { - var pos = alignmentPattern.getPositions(version); - - for (var i = 0; i < pos.length; i++) { - var row = pos[i][0]; - var col = pos[i][1]; - - for (var r = -2; r <= 2; r++) { - for (var c = -2; c <= 2; c++) { - if (r === -2 || r === 2 || c === -2 || c === 2 || - (r === 0 && c === 0)) { - matrix.set(row + r, col + c, true, true); - } else { - matrix.set(row + r, col + c, false, true); - } - } - } - } - } - - /** - * Add version info bits to matrix - * - * @param {BitMatrix} matrix Modules matrix - * @param {Number} version QR Code version - */ - function setupVersionInfo (matrix, version$1) { - var size = matrix.size; - var bits = version.getEncodedBits(version$1); - var row, col, mod; - - for (var i = 0; i < 18; i++) { - row = Math.floor(i / 3); - col = i % 3 + size - 8 - 3; - mod = ((bits >> i) & 1) === 1; - - matrix.set(row, col, mod, true); - matrix.set(col, row, mod, true); - } - } - - /** - * Add format info bits to matrix - * - * @param {BitMatrix} matrix Modules matrix - * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level - * @param {Number} maskPattern Mask pattern reference value - */ - function setupFormatInfo (matrix, errorCorrectionLevel, maskPattern) { - var size = matrix.size; - var bits = formatInfo.getEncodedBits(errorCorrectionLevel, maskPattern); - var i, mod; - - for (i = 0; i < 15; i++) { - mod = ((bits >> i) & 1) === 1; - - // vertical - if (i < 6) { - matrix.set(i, 8, mod, true); - } else if (i < 8) { - matrix.set(i + 1, 8, mod, true); - } else { - matrix.set(size - 15 + i, 8, mod, true); - } - - // horizontal - if (i < 8) { - matrix.set(8, size - i - 1, mod, true); - } else if (i < 9) { - matrix.set(8, 15 - i - 1 + 1, mod, true); - } else { - matrix.set(8, 15 - i - 1, mod, true); - } - } - - // fixed module - matrix.set(size - 8, 8, 1, true); - } - - /** - * Add encoded data bits to matrix - * - * @param {BitMatrix} matrix Modules matrix - * @param {Buffer} data Data codewords - */ - function setupData (matrix, data) { - var size = matrix.size; - var inc = -1; - var row = size - 1; - var bitIndex = 7; - var byteIndex = 0; - - for (var col = size - 1; col > 0; col -= 2) { - if (col === 6) col--; - - while (true) { - for (var c = 0; c < 2; c++) { - if (!matrix.isReserved(row, col - c)) { - var dark = false; - - if (byteIndex < data.length) { - dark = (((data[byteIndex] >>> bitIndex) & 1) === 1); - } - - matrix.set(row, col - c, dark); - bitIndex--; - - if (bitIndex === -1) { - byteIndex++; - bitIndex = 7; - } - } - } - - row += inc; - - if (row < 0 || size <= row) { - row -= inc; - inc = -inc; - break - } - } - } - } - - /** - * Create encoded codewords from data input - * - * @param {Number} version QR Code version - * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level - * @param {ByteData} data Data input - * @return {Buffer} Buffer containing encoded codewords - */ - function createData (version, errorCorrectionLevel, segments) { - // Prepare data buffer - var buffer = new bitBuffer(); - - segments.forEach(function (data) { - // prefix data with mode indicator (4 bits) - buffer.put(data.mode.bit, 4); - - // Prefix data with character count indicator. - // The character count indicator is a string of bits that represents the - // number of characters that are being encoded. - // The character count indicator must be placed after the mode indicator - // and must be a certain number of bits long, depending on the QR version - // and data mode - // @see {@link Mode.getCharCountIndicator}. - buffer.put(data.getLength(), mode.getCharCountIndicator(data.mode, version)); - - // add binary data sequence to buffer - data.write(buffer); - }); - - // Calculate required number of bits - var totalCodewords = utils.getSymbolTotalCodewords(version); - var ecTotalCodewords = errorCorrectionCode.getTotalCodewordsCount(version, errorCorrectionLevel); - var dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8; - - // Add a terminator. - // If the bit string is shorter than the total number of required bits, - // a terminator of up to four 0s must be added to the right side of the string. - // If the bit string is more than four bits shorter than the required number of bits, - // add four 0s to the end. - if (buffer.getLengthInBits() + 4 <= dataTotalCodewordsBits) { - buffer.put(0, 4); - } - - // If the bit string is fewer than four bits shorter, add only the number of 0s that - // are needed to reach the required number of bits. - - // After adding the terminator, if the number of bits in the string is not a multiple of 8, - // pad the string on the right with 0s to make the string's length a multiple of 8. - while (buffer.getLengthInBits() % 8 !== 0) { - buffer.putBit(0); - } - - // Add pad bytes if the string is still shorter than the total number of required bits. - // Extend the buffer to fill the data capacity of the symbol corresponding to - // the Version and Error Correction Level by adding the Pad Codewords 11101100 (0xEC) - // and 00010001 (0x11) alternately. - var remainingByte = (dataTotalCodewordsBits - buffer.getLengthInBits()) / 8; - for (var i = 0; i < remainingByte; i++) { - buffer.put(i % 2 ? 0x11 : 0xEC, 8); - } - - return createCodewords(buffer, version, errorCorrectionLevel) - } - - /** - * Encode input data with Reed-Solomon and return codewords with - * relative error correction bits - * - * @param {BitBuffer} bitBuffer Data to encode - * @param {Number} version QR Code version - * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level - * @return {Buffer} Buffer containing encoded codewords - */ - function createCodewords (bitBuffer, version, errorCorrectionLevel) { - // Total codewords for this QR code version (Data + Error correction) - var totalCodewords = utils.getSymbolTotalCodewords(version); - - // Total number of error correction codewords - var ecTotalCodewords = errorCorrectionCode.getTotalCodewordsCount(version, errorCorrectionLevel); - - // Total number of data codewords - var dataTotalCodewords = totalCodewords - ecTotalCodewords; - - // Total number of blocks - var ecTotalBlocks = errorCorrectionCode.getBlocksCount(version, errorCorrectionLevel); - - // Calculate how many blocks each group should contain - var blocksInGroup2 = totalCodewords % ecTotalBlocks; - var blocksInGroup1 = ecTotalBlocks - blocksInGroup2; - - var totalCodewordsInGroup1 = Math.floor(totalCodewords / ecTotalBlocks); - - var dataCodewordsInGroup1 = Math.floor(dataTotalCodewords / ecTotalBlocks); - var dataCodewordsInGroup2 = dataCodewordsInGroup1 + 1; - - // Number of EC codewords is the same for both groups - var ecCount = totalCodewordsInGroup1 - dataCodewordsInGroup1; - - // Initialize a Reed-Solomon encoder with a generator polynomial of degree ecCount - var rs = new reedSolomonEncoder(ecCount); - - var offset = 0; - var dcData = new Array(ecTotalBlocks); - var ecData = new Array(ecTotalBlocks); - var maxDataSize = 0; - var buffer = new typedarrayBuffer(bitBuffer.buffer); - - // Divide the buffer into the required number of blocks - for (var b = 0; b < ecTotalBlocks; b++) { - var dataSize = b < blocksInGroup1 ? dataCodewordsInGroup1 : dataCodewordsInGroup2; - - // extract a block of data from buffer - dcData[b] = buffer.slice(offset, offset + dataSize); - - // Calculate EC codewords for this data block - ecData[b] = rs.encode(dcData[b]); - - offset += dataSize; - maxDataSize = Math.max(maxDataSize, dataSize); - } - - // Create final data - // Interleave the data and error correction codewords from each block - var data = new typedarrayBuffer(totalCodewords); - var index = 0; - var i, r; - - // Add data codewords - for (i = 0; i < maxDataSize; i++) { - for (r = 0; r < ecTotalBlocks; r++) { - if (i < dcData[r].length) { - data[index++] = dcData[r][i]; - } - } - } - - // Apped EC codewords - for (i = 0; i < ecCount; i++) { - for (r = 0; r < ecTotalBlocks; r++) { - data[index++] = ecData[r][i]; - } - } - - return data - } - - /** - * Build QR Code symbol - * - * @param {String} data Input string - * @param {Number} version QR Code version - * @param {ErrorCorretionLevel} errorCorrectionLevel Error level - * @return {Object} Object containing symbol data - */ - function createSymbol (data, version$1, errorCorrectionLevel) { - var segments$1; - - if (isarray(data)) { - segments$1 = segments.fromArray(data); - } else if (typeof data === 'string') { - var estimatedVersion = version$1; - - if (!estimatedVersion) { - var rawSegments = segments.rawSplit(data); - - // Estimate best version that can contain raw splitted segments - estimatedVersion = version.getBestVersionForData(rawSegments, - errorCorrectionLevel); - } - - // Build optimized segments - // If estimated version is undefined, try with the highest version - segments$1 = segments.fromString(data, estimatedVersion); - } else { - throw new Error('Invalid data') - } - - // Get the min version that can contain data - var bestVersion = version.getBestVersionForData(segments$1, - errorCorrectionLevel); - - // If no version is found, data cannot be stored - if (!bestVersion) { - throw new Error('The amount of data is too big to be stored in a QR Code') - } - - // If not specified, use min version as default - if (!version$1) { - version$1 = bestVersion; - - // Check if the specified version can contain the data - } else if (version$1 < bestVersion) { - throw new Error('\n' + - 'The chosen QR Code version cannot contain this amount of data.\n' + - 'Minimum version required to store current data is: ' + bestVersion + '.\n' - ) - } - - var dataBits = createData(version$1, errorCorrectionLevel, segments$1); - - // Allocate matrix buffer - var moduleCount = utils.getSymbolSize(version$1); - var modules = new bitMatrix(moduleCount); - - // Add function modules - setupFinderPattern(modules, version$1); - setupTimingPattern(modules); - setupAlignmentPattern(modules, version$1); - - // Add temporary dummy bits for format info just to set them as reserved. - // This is needed to prevent these bits from being masked by {@link MaskPattern.applyMask} - // since the masking operation must be performed only on the encoding region. - // These blocks will be replaced with correct values later in code. - setupFormatInfo(modules, errorCorrectionLevel, 0); - - if (version$1 >= 7) { - setupVersionInfo(modules, version$1); - } - - // Add data codewords - setupData(modules, dataBits); - - // Find best mask pattern - var maskPattern$1 = maskPattern.getBestMask(modules, - setupFormatInfo.bind(null, modules, errorCorrectionLevel)); - - // Apply mask pattern - maskPattern.applyMask(maskPattern$1, modules); - - // Replace format info bits with correct values - setupFormatInfo(modules, errorCorrectionLevel, maskPattern$1); - - return { - modules: modules, - version: version$1, - errorCorrectionLevel: errorCorrectionLevel, - maskPattern: maskPattern$1, - segments: segments$1 - } - } - - /** - * QR Code - * - * @param {String | Array} data Input data - * @param {Object} options Optional configurations - * @param {Number} options.version QR Code version - * @param {String} options.errorCorrectionLevel Error correction level - * @param {Function} options.toSJISFunc Helper func to convert utf8 to sjis - */ - var create = function create (data, options) { - if (typeof data === 'undefined' || data === '') { - throw new Error('No input text') - } - - var errorCorrectionLevel$1 = errorCorrectionLevel.M; - var version$1; - - if (typeof options !== 'undefined') { - // Use higher error correction level as default - errorCorrectionLevel$1 = errorCorrectionLevel.from(options.errorCorrectionLevel, errorCorrectionLevel.M); - version$1 = version.from(options.version); - - if (options.toSJISFunc) { - utils.setToSJISFunction(options.toSJISFunc); - } - } - - return createSymbol(data, version$1, errorCorrectionLevel$1) - }; - - var qrcode = { - create: create - }; - - function hex2rgba (hex) { - if (typeof hex !== 'string') { - throw new Error('Color should be defined as hex string') - } - - var hexCode = hex.slice().replace('#', '').split(''); - if (hexCode.length < 3 || hexCode.length === 5 || hexCode.length > 8) { - throw new Error('Invalid hex color: ' + hex) - } - - // Convert from short to long form (fff -> ffffff) - if (hexCode.length === 3 || hexCode.length === 4) { - hexCode = Array.prototype.concat.apply([], hexCode.map(function (c) { - return [c, c] - })); - } - - // Add default alpha value - if (hexCode.length === 6) hexCode.push('F', 'F'); - - var hexValue = parseInt(hexCode.join(''), 16); - - return { - r: (hexValue >> 24) & 255, - g: (hexValue >> 16) & 255, - b: (hexValue >> 8) & 255, - a: hexValue & 255 - } - } - - var getOptions = function getOptions (options) { - if (!options) options = {}; - if (!options.color) options.color = {}; - - var margin = typeof options.margin === 'undefined' || - options.margin === null || - options.margin < 0 ? 4 : options.margin; - - return { - scale: options.scale || 4, - margin: margin, - color: { - dark: hex2rgba(options.color.dark || '#000000ff'), - light: hex2rgba(options.color.light || '#ffffffff') - }, - type: options.type, - rendererOpts: options.rendererOpts || {} - } - }; - - var qrToImageData = function qrToImageData (imgData, qr, margin, scale, color) { - var size = qr.modules.size; - var data = qr.modules.data; - var scaledMargin = margin * scale; - var symbolSize = size * scale + scaledMargin * 2; - var palette = [color.light, color.dark]; - - for (var i = 0; i < symbolSize; i++) { - for (var j = 0; j < symbolSize; j++) { - var posDst = (i * symbolSize + j) * 4; - var pxColor = color.light; - - if (i >= scaledMargin && j >= scaledMargin && - i < symbolSize - scaledMargin && j < symbolSize - scaledMargin) { - var iSrc = Math.floor((i - scaledMargin) / scale); - var jSrc = Math.floor((j - scaledMargin) / scale); - pxColor = palette[data[iSrc * size + jSrc]]; - } - - imgData[posDst++] = pxColor.r; - imgData[posDst++] = pxColor.g; - imgData[posDst++] = pxColor.b; - imgData[posDst] = pxColor.a; - } - } - }; - - var utils$1 = { - getOptions: getOptions, - qrToImageData: qrToImageData - }; - - var canvas = createCommonjsModule(function (module, exports) { - function clearCanvas (ctx, canvas, size) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - - if (!canvas.style) canvas.style = {}; - canvas.height = size; - canvas.width = size; - canvas.style.height = size + 'px'; - canvas.style.width = size + 'px'; - } - - function getCanvasElement () { - try { - return document.createElement('canvas') - } catch (e) { - throw new Error('You need to specify a canvas element') - } - } - - exports.render = function render (qrData, canvas, options) { - var opts = options; - var canvasEl = canvas; - - if (typeof opts === 'undefined' && (!canvas || !canvas.getContext)) { - opts = canvas; - canvas = undefined; - } - - if (!canvas) { - canvasEl = getCanvasElement(); - } - - opts = utils$1.getOptions(opts); - var size = (qrData.modules.size + opts.margin * 2) * opts.scale; - - var ctx = canvasEl.getContext('2d'); - var image = ctx.createImageData(size, size); - utils$1.qrToImageData(image.data, qrData, opts.margin, opts.scale, opts.color); - - clearCanvas(ctx, canvasEl, size); - ctx.putImageData(image, 0, 0); - - return canvasEl - }; - - exports.renderToDataURL = function renderToDataURL (qrData, canvas, options) { - var opts = options; - - if (typeof opts === 'undefined' && (!canvas || !canvas.getContext)) { - opts = canvas; - canvas = undefined; - } - - if (!opts) opts = {}; - - var canvasEl = exports.render(qrData, canvas, opts); - - var type = opts.type || 'image/png'; - var rendererOpts = opts.rendererOpts || {}; - - return canvasEl.toDataURL(type, rendererOpts.quality) - }; - }); - var canvas_1 = canvas.render; - var canvas_2 = canvas.renderToDataURL; - - function getColorAttrib (color) { - return 'fill="rgb(' + [color.r, color.g, color.b].join(',') + ')" ' + - 'fill-opacity="' + (color.a / 255).toFixed(2) + '"' - } - - var render = function render (qrData, options) { - var opts = utils$1.getOptions(options); - var size = qrData.modules.size; - var data = qrData.modules.data; - var qrcodesize = (size + opts.margin * 2) * opts.scale; - - var xmlStr = '\n'; - xmlStr += '\n'; - - xmlStr += '\n'; - xmlStr += '\n'; - xmlStr += '\n'; - - for (var i = 0; i < size; i++) { - for (var j = 0; j < size; j++) { - if (!data[i * size + j]) continue - - var x = (opts.margin + j) * opts.scale; - var y = (opts.margin + i) * opts.scale; - xmlStr += '\n'; - } - } - - xmlStr += '\n'; - xmlStr += ''; - - return xmlStr - }; - - var svgRender = { - render: render - }; - - var browser = createCommonjsModule(function (module, exports) { - function renderCanvas (renderFunc, canvas, text, opts, cb) { - var argsNum = arguments.length - 1; - if (argsNum < 2) { - throw new Error('Too few arguments provided') - } - - if (argsNum === 2) { - cb = text; - text = canvas; - canvas = opts = undefined; - } else if (argsNum === 3) { - if (canvas.getContext && typeof cb === 'undefined') { - cb = opts; - opts = undefined; - } else { - cb = opts; - opts = text; - text = canvas; - canvas = undefined; - } - } - - if (typeof cb !== 'function') { - throw new Error('Callback required as last argument') - } - - try { - var data = qrcode.create(text, opts); - cb(null, renderFunc(data, canvas, opts)); - } catch (e) { - cb(e); - } - } - - exports.create = qrcode.create; - exports.toCanvas = renderCanvas.bind(null, canvas.render); - exports.toDataURL = renderCanvas.bind(null, canvas.renderToDataURL); - - // only svg for now. - exports.toString = renderCanvas.bind(null, function (data, _, opts) { - return svgRender.render(data, opts) - }); - - /** - * Legacy API - */ - exports.qrcodedraw = function () { - return { - draw: exports.toCanvas - } - }; - }); - var browser_1 = browser.create; - var browser_2 = browser.toCanvas; - var browser_3 = browser.toDataURL; - var browser_4 = browser.qrcodedraw; - - var isMobile = function isMobile() { - return navigator && ('userAgent' in navigator && navigator.userAgent.match(/iPhone|iPod|iPad|Android/i) || navigator.maxTouchPoints > 1 && navigator.platform === 'MacIntel'); - }; - - var removeLoader = function removeLoader(element) { - while (element.firstChild) { - element.removeChild(element.firstChild); - } - }; - - var haveStyleSheet = false; - - var setLoader = function setLoader(element, styles) { - var loaderClass = "".concat(styles.prefix || 'wwp_', "qrcode_loader"); - var loader = document.createElement('div'); - loader.className = loaderClass; - loader.innerHTML = "
\n
\n
\n
"); - - if (!haveStyleSheet) { - var style = document.createElement('style'); - style.innerHTML = "@keyframes ".concat(styles.prefix || 'wwp_', "pulse {\n 0% { opacity: 1; }\n 100% { opacity: 0; }\n }\n .").concat(loaderClass, " {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: space-around;\n align-items: center;\n width: 30%;\n height: 30%;\n margin-left: 35%;\n padding-top: 35%;\n }\n .").concat(loaderClass, "_blk {\n height: 35%;\n width: 35%;\n animation: ").concat(styles.prefix || 'wwp_', "pulse 0.75s ease-in infinite alternate;\n background-color: #cccccc;\n }\n .").concat(loaderClass, "_delay {\n animation-delay: 0.75s;\n }"); - document.getElementsByTagName('head')[0].appendChild(style); - haveStyleSheet = true; - } - - removeLoader(element); - element.appendChild(loader); - }; - - var setRefersh = function setRefersh(element, error) { - var httpsRequired = error instanceof WWPassError && error.code === WWPASS_STATUS.SSL_REQUIRED; - var offline = window.navigator.onLine !== undefined && !window.navigator.onLine; - var wrapper = document.createElement('div'); - wrapper.style.display = 'flex'; - wrapper.style.alignItems = 'center'; - wrapper.style.height = '100%'; - wrapper.style.width = '100%'; - var refreshNote = document.createElement('div'); - refreshNote.style.margin = '0 10%'; - refreshNote.style.width = '80%'; - refreshNote.style.textAlign = 'center'; - refreshNote.style.overflow = 'hidden'; - var text = 'Error occured'; - - if (httpsRequired) { - text = 'Please use HTTPS'; - } else if (offline) { - text = 'No internet connection'; - } - - refreshNote.innerHTML = "

".concat(text, "

"); - var refreshButton = null; - - if (!httpsRequired) { - refreshButton = document.createElement('a'); - refreshButton.textContent = 'Retry'; - refreshButton.style.fontWeight = '400'; - refreshButton.style.fontFamily = '"Arial", sans-serif'; - refreshButton.style.fontSize = '1.2em'; - refreshButton.style.lineHeight = '1.7em'; - refreshButton.style.cursor = 'pointer'; - refreshButton.href = '#'; - refreshNote.appendChild(refreshButton); - } - - wrapper.appendChild(refreshNote); // eslint-disable-next-line no-console - - console.error("Error in WWPass Library: ".concat(error)); - removeLoader(element); - element.appendChild(wrapper); - return httpsRequired ? Promise.reject(error.message) : new Promise(function (resolve) { - // Refresh after 1 minute or on click - setTimeout(function () { - resolve({ - refresh: true - }); - }, 60000); - refreshButton.addEventListener('click', function (event) { - resolve({ - refresh: true - }); - event.preventDefault(); - }); - - if (offline) { - window.addEventListener('online', function () { - return resolve({ - refresh: true - }); - }); - } - }); - }; - - var debouncePageVisibilityFactory = function debouncePageVisibilityFactory() { - var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'visible'; - var debounce = null; - return function (fn) { - debounce = fn; - - var onDebounce = function onDebounce() { - if (document.visibilityState === state) { - debounce(); - document.removeEventListener('visibilitychange', onDebounce); - } - }; - - if (document.visibilityState === state) { - debounce(); - } else { - document.addEventListener('visibilitychange', onDebounce); - } - }; - }; - - var debouncePageVisible = debouncePageVisibilityFactory(); - - var QRCodePromise = function QRCodePromise(parentElement, wwpassURLoptions, ttl, qrcodeStyle) { - return new Promise(function (resolve) { - var QRCodeElement = document.createElement('canvas'); - browser.toCanvas(QRCodeElement, getUniversalURL(wwpassURLoptions, false), qrcodeStyle || {}, function (error) { - if (error) { - throw error; - } - }); - - if (qrcodeStyle) { - QRCodeElement.className = "".concat(qrcodeStyle.prefix, "qrcode_canvas"); - QRCodeElement.style.max_width = "".concat(qrcodeStyle.width, "px"); - QRCodeElement.style.max_height = "".concat(qrcodeStyle.width, "px"); - } - - QRCodeElement.style.height = '100%'; - QRCodeElement.style.width = '100%'; - - if (isMobile()) { - // Wrapping QRCode canvas in - var universalLinkElement = document.createElement('a'); - universalLinkElement.href = getUniversalURL(wwpassURLoptions); - universalLinkElement.appendChild(QRCodeElement); - universalLinkElement.addEventListener('click', function () { - resolve({ - away: true - }); - }); - QRCodeElement = universalLinkElement; - } - - removeLoader(parentElement); - parentElement.appendChild(QRCodeElement); - setTimeout(function () { - debouncePageVisible(function () { - resolve({ - refresh: true - }); - }); - }, ttl * 900); - }); - }; - - var clearQRCode = function clearQRCode(parentElement, style) { - return setLoader(parentElement, style); - }; - - // const DEFAULT_WAIT_CLASS = 'focused'; - // style.transition = 'all .4s ease-out'; - // style.opacity = '.3'; - - var PROTOCOL_VERSION = 2; - var WAIT_ON_CLICK = 2000; - var WAIT_ON_ERROR = 500; - - function wait(ms) { - if (ms) return new Promise(function (r) { - return setTimeout(r, ms); - }); - return null; - } - - var tryQRCodeAuth = - /*#__PURE__*/ - function () { - var _ref = asyncToGenerator( - /*#__PURE__*/ - regenerator.mark(function _callee(options) { - var log, json, response, ticket, ttl, key, wwpassURLoptions, result; - return regenerator.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - log = options.log; - _context.prev = 1; - log(options); - clearQRCode(options.qrcode, options.qrcodeStyle); - _context.next = 6; - return getTicket(options.ticketURL); - - case 6: - json = _context.sent; - response = ticketAdapter(json); - ticket = response.ticket; - ttl = response.ttl; - _context.next = 12; - return getClientNonceWrapper(ticket, ttl); - - case 12: - key = _context.sent; - wwpassURLoptions = { - universal: options.universal, - ticket: ticket, - callbackURL: options.callbackURL, - ppx: options.ppx, - version: PROTOCOL_VERSION, - clientKey: key ? encodeClientKey(key) : undefined - }; - _context.next = 16; - return Promise.race([QRCodePromise(options.qrcode, wwpassURLoptions, ttl, options.qrcodeStyle), getWebSocketResult({ - callbackURL: options.callbackURL, - ticket: ticket, - log: log, - development: options.development, - version: options.version, - ppx: options.ppx, - spfewsAddress: options.spfewsAddress, - returnErrors: options.returnErrors - })]); - - case 16: - result = _context.sent; - clearQRCode(options.qrcode, options.qrcodeStyle); - - if (!result.refresh) { - _context.next = 20; - break; - } - - return _context.abrupt("return", { - status: WWPASS_STATUS.CONTINUE, - reason: 'Need to refresh QRCode' - }); - - case 20: - if (result.clientKey && options.catchClientKey) { - options.catchClientKey(result.clientKey); - } - - if (!result.away) { - _context.next = 24; - break; - } - - closeConnectionPool(); - return _context.abrupt("return", { - status: WWPASS_STATUS.OK, - reason: 'User clicked on QRCode' - }); - - case 24: - return _context.abrupt("return", result); - - case 27: - _context.prev = 27; - _context.t0 = _context["catch"](1); - - if (_context.t0.status) { - _context.next = 35; - break; - } - - log('QRCode auth error', _context.t0); - _context.next = 33; - return setRefersh(options.qrcode, _context.t0); - - case 33: - clearQRCode(options.qrcode, options.qrcodeStyle); - return _context.abrupt("return", { - status: WWPASS_STATUS.NETWORK_ERROR, - reason: _context.t0 - }); - - case 35: - clearQRCode(options.qrcode, options.qrcodeStyle); - - if (!(_context.t0.status === WWPASS_STATUS.INTERNAL_ERROR || options.returnErrors)) { - _context.next = 39; - break; - } - - navigateToCallback(_context.t0); - return _context.abrupt("return", _context.t0); - - case 39: - if (_context.t0.status === WWPASS_STATUS.TICKET_TIMEOUT) { - log('ticket timed out'); - } - - return _context.abrupt("return", _context.t0); - - case 41: - case "end": - return _context.stop(); - } - } - }, _callee, null, [[1, 27]]); - })); - - return function tryQRCodeAuth(_x) { - return _ref.apply(this, arguments); - }; - }(); - - var getDelay = function getDelay(status) { - switch (status) { - case WWPASS_STATUS.OK: - return WAIT_ON_CLICK; - - case WWPASS_STATUS.CONTINUE: - return 0; - - default: - return WAIT_ON_ERROR; - } - }; - /* - * WWPass QR code auth function - * - options = { - 'ticketURL': undefined, // string - 'callbackURL': undefined, // string - 'development': false, // work with dev server - 'log': function (message) || console.log, // another log handler - } - */ - - - var wwpassQRCodeAuth = - /*#__PURE__*/ - function () { - var _ref2 = asyncToGenerator( - /*#__PURE__*/ - regenerator.mark(function _callee2(initialOptions) { - var defaultOptions, options, result; - return regenerator.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - defaultOptions = { - universal: false, - ticketURL: undefined, - callbackURL: undefined, - development: false, - once: false, - // Repeat authentication while possible - version: 2, - ppx: 'wwp_', - spfewsAddress: 'wss://spfews.wwpass.com', - qrcodeStyle: { - width: 256, - prefix: 'wwp_' - }, - log: function log() {} - }; - options = objectSpread({}, defaultOptions, initialOptions); - options.qrcodeStyle = objectSpread({}, defaultOptions.qrcodeStyle, initialOptions.qrcodeStyle); - - if (options.ticketURL) { - _context2.next = 5; - break; - } - - throw Error('ticketURL not found'); - - case 5: - if (options.callbackURL) { - _context2.next = 7; - break; - } - - throw Error('callbackURL not found'); - - case 7: - if (options.qrcode) { - _context2.next = 9; - break; - } - - throw Error('Element not found'); - - case 9: - _context2.next = 11; - return tryQRCodeAuth(options); - - case 11: - result = _context2.sent; - - if (!(options.once && result.status !== WWPASS_STATUS.CONTINUE)) { - _context2.next = 14; - break; - } - - return _context2.abrupt("return", result); - - case 14: - _context2.next = 16; - return wait(getDelay(result.status)); - - case 16: - if (document.documentElement.contains(options.qrcode)) { - _context2.next = 9; - break; - } - - case 17: - return _context2.abrupt("return", { - status: WWPASS_STATUS.TERMINAL_ERROR, - reason: 'QRCode element is not in DOM' - }); - - case 18: - case "end": - return _context2.stop(); - } - } - }, _callee2); - })); - - return function wwpassQRCodeAuth(_x2) { - return _ref2.apply(this, arguments); - }; - }(); - - var openWithTicket = function openWithTicket(initialOptions) { - return new Promise(function (resolve) { - var defaultOptions = { - ticket: '', - ttl: 120, - callbackURL: '', - ppx: 'wwp_', - away: true - }; - - var options = objectSpread({}, defaultOptions, initialOptions); - - if (isClientKeyTicket(options.ticket)) { - generateClientNonce(options.ticket, options.ttl).then(function (key) { - options = objectSpread({}, options, { - clientKey: encodeClientKey(key) - }); - var url = getUniversalURL(options); - - if (options.away) { - window.location.href = url; - } else { - resolve(url); - } - }); - } else { - var url = getUniversalURL(options); - - if (options.away) { - window.location.href = url; - } else { - resolve(url); - } - } - }); - }; - - var prefix = window.location.protocol === 'https:' ? 'https:' : 'http:'; - var CSS = "".concat(prefix, "//cdn.wwpass.com/packages/wwpass.js/2.4/wwpass.js.css"); - - var isNativeMessaging = function isNativeMessaging() { - var _navigator = navigator, - userAgent = _navigator.userAgent; - var re = /Firefox\/([0-9]+)\./; - var match = userAgent.match(re); - - if (match && match.length > 1) { - var version = match[1]; - - if (Number(version) >= 51) { - return 'Firefox'; - } - } - - re = /Chrome\/([0-9]+)\./; - match = userAgent.match(re); - - if (match && match.length > 1) { - var _version = match[1]; - - if (Number(_version) >= 45) { - return 'Chrome'; - } - } - - return false; - }; - - var wwpassPlatformName = function wwpassPlatformName() { - var _navigator2 = navigator, - userAgent = _navigator2.userAgent; - var knownPlatforms = ['Android', 'iPhone', 'iPad']; - - for (var i = 0; i < knownPlatforms.length; i += 1) { - if (userAgent.search(new RegExp(knownPlatforms[i], 'i')) !== -1) { - return knownPlatforms[i]; - } - } - - return null; - }; - - var wwpassMessageForPlatform = function wwpassMessageForPlatform(platformName) { - return "".concat(WWPASS_UNSUPPORTED_PLATFORM_MSG_TMPL, " ").concat(platformName); - }; - - var wwpassShowError = function wwpassShowError(message, title, onCloseCallback) { - if (!document.getElementById('_wwpass_css')) { - var l = document.createElement('link'); - l.id = '_wwpass_css'; - l.rel = 'stylesheet'; - l.href = CSS; - document.head.appendChild(l); - } - - var dlg = document.createElement('div'); - dlg.id = '_wwpass_err_dlg'; - var dlgClose = document.createElement('span'); - dlgClose.innerHTML = 'Close'; - dlgClose.id = '_wwpass_err_close'; - var header = document.createElement('h1'); - header.innerHTML = title; - var text = document.createElement('div'); - text.innerHTML = message; - dlg.appendChild(header); - dlg.appendChild(text); - dlg.appendChild(dlgClose); - document.body.appendChild(dlg); - document.getElementById('_wwpass_err_close').addEventListener('click', function () { - var elem = document.getElementById('_wwpass_err_dlg'); - elem.parentNode.removeChild(elem); - onCloseCallback(); - return false; - }); - return true; - }; - - var wwpassNoSoftware = function wwpassNoSoftware(code, onclose) { - if (code === WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND) { - var client = isNativeMessaging(); - var message = ''; - - if (client) { - if (client === 'Chrome') { - var returnURL = encodeURIComponent(window.location.href); - message = '

The WWPass Authentication extension for Chrome is not installed or is disabled in browser settings.'; - message += '

Click the link below to install and enable the WWPass Authentication extension.'; - message += "

Install WWPass Authentication Extension"); - } else if (client === 'Firefox') { - // Firefox - var _returnURL = encodeURIComponent(window.location.href); - - message = '

The WWPass Authentication extension for Firefox is not installed or is disabled in browser settings.'; - message += '

Click the link below to install and enable the WWPass Authentication extension.'; - message += "

Install WWPass Authentication Extension"); - } - } else { - message = '

No Security Pack is found on your computer or WWPass Browser Plugin is disabled.

To install Security Pack visit Key Services or check plugin settings of your browser to activate WWPass Browser Plugin.

Learn more...

'; - } - - wwpassShowError(message, 'WWPass — No Software Found', onclose); - } else if (code === WWPASS_STATUS.UNSUPPORTED_PLATFORM) { - wwpassShowError(wwpassMessageForPlatform(wwpassPlatformName()), 'WWPass — Unsupported Platform', onclose); - } - }; - - var renderPassKeyButton = function renderPassKeyButton() { - var button = document.createElement('button'); - button.innerHTML = ' Log in with PassKey'; - button.setAttribute('style', 'color: white; background-color: #2277E6; font-weight: 400; font-size: 18px; line-height: 36px; font-family: "Arial", sans-serif; padding-right: 15px; cursor: pointer; height: 40px; width: 255px; border-radius: 3px; border: 1px solid #2277E6; padding-left: 60px; text-decoration: none; position: relative;'); - return button; - }; - - var PLUGIN_OBJECT_ID = '_wwpass_plugin'; - var PLUGIN_MIME_TYPE = 'application/x-wwauth'; - var PLUGIN_TIMEOUT = 10000; - var REDUCED_PLUGIN_TIMEOUT = 1000; - var PLUGIN_AUTH_KEYTYPE_REVISION = 9701; - var PluginInfo = {}; - var savedPluginInstance; - var pendingReqests = []; - - var havePlugin = function havePlugin() { - return navigator.mimeTypes[PLUGIN_MIME_TYPE] !== undefined; - }; - - var wwpassPluginShowsErrors = function wwpassPluginShowsErrors(pluginVersionString) { - if (typeof pluginVersionString === 'string') { - var pluginVersion = pluginVersionString.split('.'); - - for (var i = 0; i < pluginVersion.length; i += 1) { - pluginVersion[i] = parseInt(pluginVersion[i], 10); - } - - if (pluginVersion.length === 3) { - if (pluginVersion[0] > 2 || pluginVersion[0] === 2 && pluginVersion[1] > 4 || pluginVersion[0] === 2 && pluginVersion[1] === 4 && pluginVersion[2] >= 1305) { - return true; - } - } - } - - return false; - }; - - var getPluginInstance = function getPluginInstance(log) { - return new Promise(function (resolve, reject) { - if (savedPluginInstance) { - if (window._wwpass_plugin_loaded !== undefined) { - // eslint-disable-line no-underscore-dangle - pendingReqests.push([resolve, reject]); - } else { - log('%s: plugin is already initialized', 'getPluginInstance'); - resolve(savedPluginInstance); - } - } else { - var junkBrowser = navigator.mimeTypes.length === 0; - var pluginInstalled = havePlugin(); - var timeout = junkBrowser ? REDUCED_PLUGIN_TIMEOUT : PLUGIN_TIMEOUT; - - if (pluginInstalled || junkBrowser) { - log('%s: trying to create plugin instance(junkBrowser=%s, timeout=%d)', 'getPluginInstance', junkBrowser, timeout); - var pluginHtml = ""); - var pluginDiv = document.createElement('div'); - pluginDiv.setAttribute('style', 'position: fixed; left: 0; top:0; width: 1px; height: 1px; z-index: -1; opacity: 0.01'); - document.body.appendChild(pluginDiv); - pluginDiv.innerHTML += pluginHtml; - savedPluginInstance = document.getElementById(PLUGIN_OBJECT_ID); - var timer = setTimeout(function () { - delete window._wwpass_plugin_loaded; // eslint-disable-line no-underscore-dangle - - savedPluginInstance = null; - log('%s: WWPass plugin loading timeout', 'getPluginInstance'); - reject({ - code: WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND, - message: WWPASS_NO_AUTH_INTERFACES_FOUND_MSG - }); - - for (var i = 0; i < pendingReqests.length; i += 1) { - var pendingReject = pendingReqests[i][1]; - pendingReject({ - code: WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND, - message: WWPASS_NO_AUTH_INTERFACES_FOUND_MSG - }); - } - }, PLUGIN_TIMEOUT); - - window._wwpass_plugin_loaded = function () { - // eslint-disable-line no-underscore-dangle - log('%s: plugin loaded', 'getPluginInstance'); - delete window._wwpass_plugin_loaded; // eslint-disable-line no-underscore-dangle - - clearTimeout(timer); - - try { - PluginInfo.versionString = savedPluginInstance.version; - PluginInfo.revision = parseInt(savedPluginInstance.version.split('.')[2], 10); - PluginInfo.showsErrors = wwpassPluginShowsErrors(PluginInfo.versionString); - } catch (err) { - log('%s: error parsing plugin version: %s', 'getPluginInstance', err); - } - - resolve(savedPluginInstance); - - for (var i = 0; i < pendingReqests.length; i += 1) { - var pendingResolve = pendingReqests[i][0]; - pendingResolve(savedPluginInstance); - } - }; - } else { - log('%s: no suitable plugins installed', 'getPluginInstance'); - reject({ - code: WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND, - message: WWPASS_NO_AUTH_INTERFACES_FOUND_MSG - }); - } - } - }); - }; - - var wrapCallback = function wrapCallback(callback) { - if (!PluginInfo.showsErrors) { - return function (code, ticketOrMessage) { - if (code !== WWPASS_STATUS.OK && code !== WWPASS_STATUS.USER_REJECT) { - var message = "

A error has occured: ".concat(ticketOrMessage, "

") + "

Learn more

"); - wwpassShowError(message, 'WWPass Error', function () { - callback(code, ticketOrMessage); - }); - } else { - callback(code, ticketOrMessage); - } - }; - } - - return callback; - }; - - var wwpassPluginExecute = function wwpassPluginExecute(inputRequest) { - return new Promise(function (resolve, reject) { - var defaultOptions = { - log: function log() {} - }; - - var request = objectSpread({}, defaultOptions, inputRequest); - - request.log('%s: called, operation name is "%s"', 'wwpassPluginExecute', request.operation || null); - getPluginInstance(request.log).then(function (plugin) { - var wrappedCallback = wrapCallback(function (code, ticketOrMessage) { - if (code === WWPASS_STATUS.OK) { - resolve(ticketOrMessage); - } else { - reject({ - code: code, - message: ticketOrMessage - }); - } - }); - - if (plugin.execute !== undefined) { - request.callback = wrappedCallback; - plugin.execute(request); - } else if (request.operation === 'auth') { - if (PluginInfo.revision < PLUGIN_AUTH_KEYTYPE_REVISION) { - plugin.authenticate(request.ticket, wrappedCallback); - } else { - plugin.authenticate(request.ticket, wrappedCallback, request.firstKeyType || WWPASS_KEY_TYPE_DEFAULT); - } - } else { - plugin.do_operation(request.operation, wrappedCallback); - } - }).catch(reject); - }); - }; - - var pluginWaitForRemoval = function pluginWaitForRemoval() { - var log = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {}; - return new Promise(function (resolve, reject) { - getPluginInstance(log).then(function (plugin) { - plugin.on_key_removed(resolve); - }).catch(reject); - }); - }; - - var EXTENSION_POLL_TIMEOUT = 200; - var EXTENSION_POLL_ATTEMPTS = 15; - var extensionNotInstalled = false; - - var timedPoll = function timedPoll(args) { - var condition = args.condition; - - if (typeof condition === 'function') { - condition = condition(); - } - - if (condition) { - args.onCondition(); - } else { - var attempts = args.attempts || 0; - - if (attempts--) { - // eslint-disable-line no-plusplus - var timeout = args.timeout || 100; - setTimeout(function (p) { - return function () { - timedPoll(p); - }; - }({ - timeout: timeout, - attempts: attempts, - condition: args.condition, - onCondition: args.onCondition, - onTimeout: args.onTimeout - }), timeout); - } else { - args.onTimeout(); - } - } - }; - - var isNativeMessagingExtensionReady = function isNativeMessagingExtensionReady() { - return (document.querySelector('meta[property="wwpass:extension:version"]') || document.getElementById('_WWAuth_Chrome_Installed_')) !== null; - }; - - var randomID = function randomID() { - return ((1 + Math.random()) * 0x100000000 | 0).toString(16).substring(1); - }; // eslint-disable-line no-bitwise,max-len - - - var wwpassNMCall = function wwpassNMCall(func, args) { - var log = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {}; - return new Promise(function (resolve, reject) { - if (extensionNotInstalled) { - log('%s: chrome native messaging extension is not installed', 'wwpassNMExecute'); - reject({ - code: WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND, - message: WWPASS_NO_AUTH_INTERFACES_FOUND_MSG - }); - return; - } - - timedPoll({ - timeout: EXTENSION_POLL_TIMEOUT, - attempts: EXTENSION_POLL_ATTEMPTS, - condition: isNativeMessagingExtensionReady, - onCondition: function onCondition() { - var id = randomID(); - window.postMessage({ - type: '_WWAuth_Message', - src: 'client', - id: id, - func: func, - args: args ? JSON.parse(JSON.stringify(args)) : args - }, '*'); - window.addEventListener('message', function onMessageCallee(event) { - if (event.data.type === '_WWAuth_Message' && event.data.src === 'plugin' && event.data.id === id) { - window.removeEventListener('message', onMessageCallee, false); - - if (event.data.code === WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND) { - var message = '

No Security Pack is found on your computer or WWPass native host is not responding.

To install Security Pack visit Key Services

Learn more...

'; - wwpassShowError(message, 'WWPass Error', function () { - reject({ - code: event.data.code, - message: event.data.ticketOrMessage - }); - }); - } else if (event.data.code === WWPASS_STATUS.OK) { - resolve(event.data.ticketOrMessage); - } else { - reject({ - code: event.data.code, - message: event.data.ticketOrMessage - }); - } - } - }, false); - }, - onTimeout: function onTimeout() { - extensionNotInstalled = true; - log('%s: chrome native messaging extension is not installed', 'wwpassNMExecute'); - reject({ - code: WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND, - message: WWPASS_NO_AUTH_INTERFACES_FOUND_MSG - }); - } - }); - }); - }; - - var wwpassNMExecute = function wwpassNMExecute(inputRequest) { - var defaultOptions = { - log: function log() {} - }; - - var request = objectSpread({}, defaultOptions, inputRequest); - - var log = request.log; - delete request.log; - log('%s: called', 'wwpassNMExecute'); - request.uri = { - domain: window.location.hostname, - protocol: window.location.protocol - }; - return wwpassNMCall('exec', [request], log); - }; - - var nmWaitForRemoval = function nmWaitForRemoval() { - var log = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : function () {}; - return wwpassNMCall('on_key_rm', undefined, log); - }; - - var pluginPresent = function pluginPresent() { - return havePlugin() || isNativeMessagingExtensionReady(); - }; - - var wwpassPlatformName$1 = function wwpassPlatformName() { - var _navigator = navigator, - userAgent = _navigator.userAgent; - var knownPlatforms = ['Android', 'iPhone', 'iPad']; - - for (var i = 0; i < knownPlatforms.length; i += 1) { - if (userAgent.search(new RegExp(knownPlatforms[i], 'i')) !== -1) { - return knownPlatforms[i]; - } - } - - return null; - }; // N.B. it call functions in REVERSE order - - - var chainedCall = function chainedCall(functions, request, resolve, reject) { - functions.pop()(request).then(resolve, function (e) { - if (e.code === WWPASS_STATUS.NO_AUTH_INTERFACES_FOUND) { - if (functions.length > 0) { - chainedCall(functions, request, resolve, reject); - } else { - wwpassNoSoftware(e.code, function () {}); - reject(e); - } - } else { - reject(e); - } - }); - }; - - var wwpassCall = function wwpassCall(nmFunc, pluginFunc, request) { - return new Promise(function (resolve, reject) { - var platformName = wwpassPlatformName$1(); - - if (platformName !== null) { - wwpassNoSoftware(WWPASS_STATUS.UNSUPPORTED_PLATFORM, function () { - reject({ - code: WWPASS_STATUS.UNSUPPORTED_PLATFORM, - message: wwpassMessageForPlatform(platformName) - }); - }); - return; - } - - if (havePlugin()) { - chainedCall([nmFunc, pluginFunc], request, resolve, reject); - } else { - chainedCall([pluginFunc, nmFunc], request, resolve, reject); - } - }); - }; - - var wwpassAuth = function wwpassAuth(request) { - return wwpassCall(wwpassNMExecute, wwpassPluginExecute, objectSpread({}, request, { - operation: 'auth' - })); - }; - - var waitForRemoval = function waitForRemoval() { - return wwpassCall(nmWaitForRemoval, pluginWaitForRemoval); - }; - - var doWWPassPasskeyAuth = function doWWPassPasskeyAuth(options) { - return getTicket(options.ticketURL).then(function (json) { - var response = ticketAdapter(json); - var ticket = response.ticket; - return getClientNonceWrapper(ticket, response.ttl).then(function (key) { - return wwpassAuth({ - ticket: ticket, - clientKeyNonce: key !== undefined ? abToB64(key) : undefined, - log: options.log - }); - }).then(function () { - return ticket; - }); - /* We may receive new ticket here but we need - * to keep the original one to find nonce */ - }); - }; - - var initPasskeyButton = function initPasskeyButton(options, resolve, reject) { - if (options.passkeyButton.innerHTML.length === 0) { - options.passkeyButton.appendChild(renderPassKeyButton()); - } - - var authUnderway = false; - options.passkeyButton.addEventListener('click', function (e) { - if (!authUnderway) { - authUnderway = true; - doWWPassPasskeyAuth(options).then(function (newTicket) { - authUnderway = false; - resolve({ - ppx: options.ppx, - version: options.version, - code: WWPASS_STATUS.OK, - message: WWPASS_OK_MSG, - ticket: newTicket, - callbackURL: options.callbackURL, - hw: true - }); - }, function (err) { - authUnderway = false; - - if (!err.code) { - options.log('passKey error', err); - } else if (err.code === WWPASS_STATUS.INTERNAL_ERROR || options.returnErrors) { - reject({ - ppx: options.ppx, - version: options.version, - code: err.code, - message: err.message, - callbackURL: options.callbackURL - }); - } - }); - } - - e.preventDefault(); - }, false); - }; - - var wwpassPasskeyAuth = function wwpassPasskeyAuth(initialOptions) { - return new Promise(function (resolve, reject) { - var defaultOptions = { - ticketURL: '', - callbackURL: '', - ppx: 'wwp_', - forcePasskeyButton: true, - log: function log() {} - }; - - var options = objectSpread({}, defaultOptions, initialOptions); - - if (!options.passkeyButton) { - reject({ - ppx: options.ppx, - version: options.version, - code: WWPASS_STATUS.INTERNAL_ERROR, - message: 'Cannot find passkey element', - callbackURL: options.callbackURL - }); - } - - if (options.forcePasskeyButton || pluginPresent()) { - if (options.passkeyButton.style.display === 'none') { - options.passkeyButton.style.display = null; - } - - initPasskeyButton(options, resolve, reject); - } else { - var displayBackup = options.passkeyButton.style.display; - options.passkeyButton.style.display = 'none'; - var observer = new MutationObserver(function (_mutationsList, _observer) { - if (pluginPresent()) { - _observer.disconnect(); - - options.passkeyButton.style.display = displayBackup === 'none' ? null : displayBackup; - initPasskeyButton(options, resolve, reject); - } - }); - observer.observe(document.head, { - childList: true - }); - } - }).then(navigateToCallback, navigateToCallback); - }; - - var absolutePath = function absolutePath(href) { - var link = document.createElement('a'); - link.href = href; - return link.href; - }; - - var authInit = function authInit(initialOptions) { - var defaultOptions = { - ticketURL: '', - callbackURL: '', - hw: false, - ppx: 'wwp_', - version: 2, - log: function log() {} - }; - - var options = objectSpread({}, defaultOptions, initialOptions); - - if (typeof options.callbackURL === 'string') { - options.callbackURL = absolutePath(options.callbackURL); - } - - options.passkeyButton = typeof options.passkey === 'string' ? document.querySelector(options.passkey) : options.passkey; - options.qrcode = typeof options.qrcode === 'string' ? document.querySelector(options.qrcode) : options.qrcode; - var promises = []; - - if (options.passkeyButton) { - promises.push(wwpassPasskeyAuth(options)); - } - - promises.push(wwpassQRCodeAuth(options)); - return Promise.race(promises); - }; - - var version$1 = "2.1.6"; - - if ('console' in window && window.console.log) { - window.console.log("WWPass frontend library version ".concat(version$1)); - } - - window.WWPass = { - authInit: authInit, - openWithTicket: openWithTicket, - isClientKeyTicket: isClientKeyTicket, - cryptoPromise: WWPassCryptoPromise, - copyClientNonce: copyClientNonce, - updateTicket: updateTicket, - pluginPresent: pluginPresent, - waitForRemoval: waitForRemoval, - STATUS: WWPASS_STATUS - }; - -}()); -//# sourceMappingURL=wwpass-frontend.js.map diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/ticket.json b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/ticket.json deleted file mode 100755 index bdff117ebee..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/ticket.json +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -if [[ "$QUERY_STRING" =~ ^p=.* ]] -then - auth_type="p" -fi - -echo "Content-type: application/json" -echo "" -curl "https://spfe.wwpass.com/get.json?auth_type=$auth_type" --cert /opt/wwpass_gluu/gluu_client.crt --key /opt/wwpass_gluu/gluu_client.key --cacert /opt/wwpass_gluu/wwpass.ca.crt -s diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.ca.crt b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.ca.crt deleted file mode 100644 index 19c91f55687..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.ca.crt +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGATCCA+mgAwIBAgIJAN7JZUlglGn4MA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV -BAYTAlVTMRswGQYDVQQKExJXV1Bhc3MgQ29ycG9yYXRpb24xKzApBgNVBAMTIldX -UGFzcyBDb3Jwb3JhdGlvbiBQcmltYXJ5IFJvb3QgQ0EwIhgPMjAxMjExMjgwOTAw -MDBaGA8yMDUyMTEyODA4NTk1OVowVzELMAkGA1UEBhMCVVMxGzAZBgNVBAoTEldX -UGFzcyBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiV1dQYXNzIENvcnBvcmF0aW9uIFBy -aW1hcnkgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMmF -pl1WX80osygWx4ZX8xGyYfHx8cpz29l5s/7mgQIYCrmUSLK9KtSryA0pmzrOFkyN -BuT0OU5ucCuv2WNgUriJZ78b8sekW1oXy2QXndZSs+CA+UoHFw0YqTEDO659/Tjk -NqlE5HMXdYvIb7jhcOAxC8gwAJFgAkQboaMIkuWsAnpOtKzrnkWHGz45qoyICjqz -feDcN0dh3ITMHXrYiwkVq5fGXHPbuJPbuBN+unnakbL3Ogk3yPnEcm6YV+HrxQ7S -Ky83q60Abdy8ft0RpSJeUkBjJVwiHu4y4j5iKC1tNgtV8qE9Zf2g5vAHzL3obqnu -IMr8JpmWp0MrrUa9jYOtKXk2LnZnfxurJ74NVk2RmuN5I/H0a/tUrHWtCE5pcVNk -b3vmoqeFsbTs2KDCMq/gzUhHU31l4Zrlz+9DfBUxlb5fNYB5lF4FnR+5/hKgo75+ -OaNjiSfp9gTH6YfFCpS0OlHmKhsRJlR2aIKpTUEG9hjSg3Oh7XlpJHhWolQQ2BeL -++3UOyRMTDSTZ1bGa92oz5nS+UUsE5noUZSjLM+KbaJjZGCxzO9y2wiFBbRSbhL2 -zXpUD2dMB1G30jZwytjn15VAMEOYizBoHEp2Nf9PNhsDGa32AcpJ2a0n89pbSOlu -yr/vEzYjJ2DZ/TWQQb7upi0G2kRX17UIZ5ZfhjmBAgMBAAGjgcswgcgwHQYDVR0O -BBYEFGu/H4b/gn8RzL7XKHBT6K4BQcl7MIGIBgNVHSMEgYAwfoAUa78fhv+CfxHM -vtcocFPorgFByXuhW6RZMFcxCzAJBgNVBAYTAlVTMRswGQYDVQQKExJXV1Bhc3Mg -Q29ycG9yYXRpb24xKzApBgNVBAMTIldXUGFzcyBDb3Jwb3JhdGlvbiBQcmltYXJ5 -IFJvb3QgQ0GCCQDeyWVJYJRp+DAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB -BjANBgkqhkiG9w0BAQsFAAOCAgEAE46CMikI7378mkC3qZyKcVxkNfLRe3eD4h04 -OO27rmfZj/cMrDDCt0Bn2t9LBUGBdXfZEn13gqn598F6lmLoObtN4QYqlyXrFcPz -FiwQarba+xq8togxjMkZ2y70MlV3/PbkKkwv4bBjOcLZQ1DsYehPdsr57C6Id4Ee -kEQs/aMtKcMzZaSipkTuXFxfxW4uBifkH++tUASD44OD2r7m1UlSQ5viiv3l0qvA -B89dPifVnIeAvPcd7+GY2RXTZCw36ZipnFiOWT9TkyTDpB/wjWQNFrgmmQvxQLeW -BWIUSaXJwlVzMztdtThnt/bNZNGPMRfaZ76OljYB9BKC7WUmss2f8toHiys+ERHz -0xfCTVhowlz8XtwWfb3A17jzJBm+KAlQsHPgeBEqtocxvBJcqhOiKDOpsKHHz+ng -exIO3elr1TCVutPTE+UczYTBRsL+jIdoIxm6aA9rrN3qDVwMnuHThSrsiwyqOXCz -zjCaCf4l5+KG5VNiYPytiGicv8PCBjwFkzIr+LRSyUiYzAZuiyRchpdT+yRAfL7q -qHBuIHYhG3E47a3GguwUwUGcXR+NjrSmteHRDONOUYUCH41hw6240Mo1lL4F+rpr -LEBB84k3+v+AtbXePEwvp+o1nu/+1sRkhqlNFHN67vakqC4xTxiuPxu6Pb/uDeNI -ip0+E9I= ------END CERTIFICATE----- diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.py deleted file mode 100644 index f31a20315ee..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpass.py +++ /dev/null @@ -1,248 +0,0 @@ -# -*- coding: utf-8 -*- -__author__="Rostislav Kondratenko " -__date__ ="$27.11.2014 18:05:15$" - -# Copyright 2009-2019 WWPASS Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pickle -from threading import Lock -import ssl -try: - # python3 - from urllib.request import urlopen - from urllib.parse import urlencode - from urllib.error import URLError -except ImportError: - # python2 - from urllib2 import urlopen, URLError - from urllib import urlencode - -DEFAULT_CADATA = u'''-----BEGIN CERTIFICATE----- -MIIGATCCA+mgAwIBAgIJAN7JZUlglGn4MA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV -BAYTAlVTMRswGQYDVQQKExJXV1Bhc3MgQ29ycG9yYXRpb24xKzApBgNVBAMTIldX -UGFzcyBDb3Jwb3JhdGlvbiBQcmltYXJ5IFJvb3QgQ0EwIhgPMjAxMjExMjgwOTAw -MDBaGA8yMDUyMTEyODA4NTk1OVowVzELMAkGA1UEBhMCVVMxGzAZBgNVBAoTEldX -UGFzcyBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiV1dQYXNzIENvcnBvcmF0aW9uIFBy -aW1hcnkgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMmF -pl1WX80osygWx4ZX8xGyYfHx8cpz29l5s/7mgQIYCrmUSLK9KtSryA0pmzrOFkyN -BuT0OU5ucCuv2WNgUriJZ78b8sekW1oXy2QXndZSs+CA+UoHFw0YqTEDO659/Tjk -NqlE5HMXdYvIb7jhcOAxC8gwAJFgAkQboaMIkuWsAnpOtKzrnkWHGz45qoyICjqz -feDcN0dh3ITMHXrYiwkVq5fGXHPbuJPbuBN+unnakbL3Ogk3yPnEcm6YV+HrxQ7S -Ky83q60Abdy8ft0RpSJeUkBjJVwiHu4y4j5iKC1tNgtV8qE9Zf2g5vAHzL3obqnu -IMr8JpmWp0MrrUa9jYOtKXk2LnZnfxurJ74NVk2RmuN5I/H0a/tUrHWtCE5pcVNk -b3vmoqeFsbTs2KDCMq/gzUhHU31l4Zrlz+9DfBUxlb5fNYB5lF4FnR+5/hKgo75+ -OaNjiSfp9gTH6YfFCpS0OlHmKhsRJlR2aIKpTUEG9hjSg3Oh7XlpJHhWolQQ2BeL -++3UOyRMTDSTZ1bGa92oz5nS+UUsE5noUZSjLM+KbaJjZGCxzO9y2wiFBbRSbhL2 -zXpUD2dMB1G30jZwytjn15VAMEOYizBoHEp2Nf9PNhsDGa32AcpJ2a0n89pbSOlu -yr/vEzYjJ2DZ/TWQQb7upi0G2kRX17UIZ5ZfhjmBAgMBAAGjgcswgcgwHQYDVR0O -BBYEFGu/H4b/gn8RzL7XKHBT6K4BQcl7MIGIBgNVHSMEgYAwfoAUa78fhv+CfxHM -vtcocFPorgFByXuhW6RZMFcxCzAJBgNVBAYTAlVTMRswGQYDVQQKExJXV1Bhc3Mg -Q29ycG9yYXRpb24xKzApBgNVBAMTIldXUGFzcyBDb3Jwb3JhdGlvbiBQcmltYXJ5 -IFJvb3QgQ0GCCQDeyWVJYJRp+DAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB -BjANBgkqhkiG9w0BAQsFAAOCAgEAE46CMikI7378mkC3qZyKcVxkNfLRe3eD4h04 -OO27rmfZj/cMrDDCt0Bn2t9LBUGBdXfZEn13gqn598F6lmLoObtN4QYqlyXrFcPz -FiwQarba+xq8togxjMkZ2y70MlV3/PbkKkwv4bBjOcLZQ1DsYehPdsr57C6Id4Ee -kEQs/aMtKcMzZaSipkTuXFxfxW4uBifkH++tUASD44OD2r7m1UlSQ5viiv3l0qvA -B89dPifVnIeAvPcd7+GY2RXTZCw36ZipnFiOWT9TkyTDpB/wjWQNFrgmmQvxQLeW -BWIUSaXJwlVzMztdtThnt/bNZNGPMRfaZ76OljYB9BKC7WUmss2f8toHiys+ERHz -0xfCTVhowlz8XtwWfb3A17jzJBm+KAlQsHPgeBEqtocxvBJcqhOiKDOpsKHHz+ng -exIO3elr1TCVutPTE+UczYTBRsL+jIdoIxm6aA9rrN3qDVwMnuHThSrsiwyqOXCz -zjCaCf4l5+KG5VNiYPytiGicv8PCBjwFkzIr+LRSyUiYzAZuiyRchpdT+yRAfL7q -qHBuIHYhG3E47a3GguwUwUGcXR+NjrSmteHRDONOUYUCH41hw6240Mo1lL4F+rpr -LEBB84k3+v+AtbXePEwvp+o1nu/+1sRkhqlNFHN67vakqC4xTxiuPxu6Pb/uDeNI -ip0+E9I= ------END CERTIFICATE----- ''' - -PIN = 'p' -SESSION_KEY = 's' -CLIENT_KEY = 'c' - -class WWPassException(IOError): - pass - -class WWPassConnection(object): - - def __init__(self, key_file, cert_file, timeout=10, spfe_addr='https://spfe.wwpass.com', cafile=None): - """Construct class. - - Args: - key_file (str): ??? - cert_file (str): ?? - timeout (int): ?? - spfe_addr (str): ?? - cafile (str): ?? - """ - - self.context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1) - self.context.load_cert_chain(certfile=cert_file, keyfile=key_file) - if cafile is None: - self.context.load_verify_locations(cadata=DEFAULT_CADATA) - else: - self.context.load_verify_locations(cafile=cafile) - self.spfe_addr = 'https://%s' % spfe_addr if spfe_addr.find('://') == -1 else spfe_addr - self.timeout = timeout - - def makeRequest(self, method, command, attempts=3,**paramsDict): - params = {k:v.encode('UTF-8') if hasattr(v,"encode") else v for k, v in paramsDict.items() if v is not None} - try: - if method == 'GET': - res = urlopen(self.spfe_addr +'/'+command+'?'+urlencode(params), context=self.context, timeout=self.timeout) - else: - res = urlopen(self.spfe_addr +'/'+command, data=urlencode(params).encode('UTF-8'), context=self.context, timeout=self.timeout) - res = pickle.loads(res.read()) - if not res['result']: - if 'code'in res: - raise WWPassException('SPFE returned error: %s: %s' %(res['code'], res['data'])) - raise WWPassException('SPFE returned error: %s' % res['data']) - return res - except URLError: - if attempts>0: - attempts -= 1 - else: - raise - return self.makeRequest(method, command, attempts,**params) - - @classmethod - def makeAuthTypeString(cls, auth_types): - valid_auth_types = (PIN, SESSION_KEY, CLIENT_KEY) - return ''.join(x for x in auth_types if x in valid_auth_types) - - def getName(self): - ticket = self.getTicket(ttl=0)['ticket'] - pos = ticket.find(':') - if pos == -1: - raise WWPassException('Cannot extract service provider name from ticket.') - return ticket[:pos] - - def getTicket(self, ttl=None, auth_types=()): - result = self.makeRequest('GET','get', ttl=ttl or None, auth_type=self.makeAuthTypeString(auth_types) or None) - return {'ticket' : result['data'], 'ttl' : result['ttl']} - - def getPUID(self, ticket, auth_types=(), finalize=None): - result = self.makeRequest('GET','puid', ticket=ticket, auth_type=self.makeAuthTypeString(auth_types) or None, finalize=finalize) - return {'puid' : result['data']} - - def putTicket(self, ticket, ttl=None, auth_types=(), finalize=None): - result = self.makeRequest('GET','put', ticket=ticket, ttl=ttl or None, auth_type=self.makeAuthTypeString(auth_types) or None, finalize=finalize) - return {'ticket' : result['data'], 'ttl' : result['ttl']} - - def readData(self, ticket, container=b'', finalize=None): - result = self.makeRequest('GET','read', ticket=ticket, container=container or None, finalize=finalize) - return {'data' : result['data']} - - def readDataAndLock(self, ticket, lockTimeout, container=b''): - result = self.makeRequest('GET','read', ticket=ticket, container=container or None, lock='1', to=lockTimeout) - return {'data' : result['data']} - - - def writeData(self, ticket, data, container=b'', finalize=None): - self.makeRequest('POST','write', ticket=ticket, data=data, container=container or None, finalize=finalize) - return True - - def writeDataAndUnlock(self, ticket, data, container=b'', finalize=None): - self.makeRequest('POST','write', ticket=ticket, data=data, container=container or None, unlock='1', finalize=finalize) - return True - - def lock(self, ticket, lockTimeout, lockid): - self.makeRequest('GET','lock',ticket=ticket, lockid=lockid, to=lockTimeout) - return True - - def unlock(self, ticket, lockid, finalize=None): - self.makeRequest('GET','unlock', ticket=ticket, lockid=lockid, finalize=finalize) - return True - - def getSessionKey(self, ticket, finalize=None): - result = self.makeRequest('GET','key', ticket=ticket, finalize=finalize) - return {'sessionKey' : result['data']} - - def createPFID(self, data=''): - if data: - result = self.makeRequest('POST','sp/create', data=data) - else: - result = self.makeRequest('GET','sp/create') - return {'pfid' : result['data']} - - def removePFID(self, pfid): - self.makeRequest('POST','sp/remove', pfid=pfid) - return True - - def readDataSP(self, pfid): - result = self.makeRequest('GET','sp/read', pfid=pfid) - return {'data' : result['data']} - - def readDataSPandLock(self, pfid, lockTimeout): - result = self.makeRequest('GET','sp/read', pfid=pfid, to=lockTimeout, lock=1) - return {'data' : result['data']} - - def writeDataSP(self, pfid, data): - self.makeRequest('POST','sp/write', pfid=pfid, data=data) - return True - - def writeDataSPandUnlock(self, pfid, data): - self.makeRequest('POST','sp/write', pfid=pfid, data=data, unlock=1) - return True - - def lockSP(self, lockid, lockTimeout): - self.makeRequest('GET','sp/lock',lockid=lockid, to=lockTimeout) - return True - - def unlockSP(self, lockid): - self.makeRequest('GET','sp/unlock',lockid=lockid) - return True - - def getClientKey(self, ticket): - result = self.makeRequest('GET','clientkey',ticket=ticket) - res_dict = {'clientKey' : result['data'], 'ttl' : result['ttl']} - if 'originalTicket' in result: - res_dict['originalTicket'] = result['originalTicket'] - return res_dict - -class WWPassConnectionMT(WWPassConnection): - - def __init__(self, key_file, cert_file, timeout=10, spfe_addr='https://spfe.wwpass.com', ca_file=None, initial_connections=2): - self.Pool = [] - self.key_file = key_file - self.cert_file = cert_file - self.ca_file = ca_file - self.timeout = timeout - self.spfe_addr = spfe_addr - for _ in range(initial_connections): - self.addConnection() - - def addConnection(self, acquired = False): - c = WWPassConnection(self.key_file, self.cert_file, self.timeout, self.spfe_addr, self.ca_file) - c.lock = Lock() - if acquired: - c.lock.acquire() - self.Pool.append(c) - return c - - def getConnection(self): - for conn in (c for c in self.Pool if c.lock.acquire(False)): - return conn - conn=self.addConnection(True) - return conn - - def makeRequest(self, method, command, attempts=3,**paramsDict): - conn = None - try: - conn = self.getConnection() - return conn.makeRequest(method, command, attempts, **paramsDict) - finally: - if conn is not None: - conn.lock.release() - -WWPASSConnection = WWPassConnection -WWPASSConnectionMT = WWPassConnectionMT diff --git a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpassauth.py b/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpassauth.py deleted file mode 100644 index eadaf673378..00000000000 --- a/jans-linux-setup/jans_setup/static/extension/person_authentication/other/wwpass/wwpassauth.py +++ /dev/null @@ -1,289 +0,0 @@ -from io.jans.service.cdi.util import CdiUtil -from io.jans.as.server.security import Identity -from org.gluu.oxauth.model.configuration import AppConfiguration -from io.jans.model.custom.script.type.auth import PersonAuthenticationType -from io.jans.as.server.service import AuthenticationService -from org.xdi.oxauth.service import UserService -from io.jans.util import StringHelper -from io.jans.service import MailService -from org.gluu.oxauth.model.configuration import AppConfiguration - -from jakarta.faces.context import FacesContext - -from com.google.common.io import BaseEncoding - -from urlparse import urlparse - -import jarray -from java.util import Arrays -from java.security import SecureRandom -import java - -from time import time - -from wwpass import WWPassConnection - - -class PersonAuthentication(PersonAuthenticationType): - EMAIL_NONCE_EXPIRATION = 600 # seconds - - def __init__(self, currentTimeMillis): - self.currentTimeMillis = currentTimeMillis - self.user = None - - @staticmethod - def generateNonce(keyLength): - bytes = jarray.zeros(keyLength, "b") - secureRandom = SecureRandom() - secureRandom.nextBytes(bytes) - return BaseEncoding.base64().omitPadding().encode(bytes) - - def init(self, configurationAttributes): - print "WWPASS. Initialization" - self.allow_email_bind = configurationAttributes.get("allow_email_bind").getValue2() if configurationAttributes.containsKey("allow_email_bind") else '' - self.allow_password_bind = configurationAttributes.get("allow_password_bind").getValue2() if configurationAttributes.containsKey("allow_password_bind") else '' - self.allow_passkey_bind = configurationAttributes.get("allow_passkey_bind").getValue2() if configurationAttributes.containsKey("allow_passkey_bind") else '' - self.registration_url = configurationAttributes.get("registration_url").getValue2() if configurationAttributes.containsKey("registration_url") else '' - self.recovery_url = configurationAttributes.get("recovery_url").getValue2() if configurationAttributes.containsKey("recovery_url") else '' - self.wwc = WWPassConnection( - configurationAttributes.get("wwpass_key_file").getValue2(), - configurationAttributes.get("wwpass_crt_file").getValue2()) - self.use_pin = configurationAttributes.get("use_pin").getValue2() if configurationAttributes.containsKey("use_pin") else None - self.auth_type = ('p',) if self.use_pin else () - self.sso_cookie_domain = '.'.join(urlparse(CdiUtil.bean(AppConfiguration).getBaseEndpoint()).netloc.split('.')[-2:]) - sso_cookie_tags = configurationAttributes.get("sso_cookie_tags").getValue2() if configurationAttributes.containsKey("sso_cookie_tags") else None - if sso_cookie_tags: - self.sso_cookie_tags = sso_cookie_tags.split(' ') - else: - self.sso_cookie_tags = [] - print "WWPASS. Initialized successfully" - return True - - def destroy(self, configurationAttributes): - print "WWPASS. Destroy" - return True - - def getApiVersion(self): - return 2 - - def isValidAuthenticationMethod(self, usageType, configurationAttributes): - return True - - def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes): - return None - - def tryFirstLogin(self, puid, userService, authenticationService): # Login user that was just registered via external link - user = userService.getUserByAttribute("oxTrustExternalId", "wwpass:%s"%puid) - if user and authenticationService.authenticate(user.getUserId()): - userService.addUserAttribute(user.getUserId(), "oxExternalUid", "wwpass:%s"%puid) - userService.removeUserAttribute(user.getUserId(),"oxTrustExternalId", "wwpass:%s"%puid) - return True - return False - - def getPuid(self, ticket): - puid = self.wwc.getPUID(ticket, self.auth_type)['puid'] - assert puid #Just in case it's empty or None - return puid - - def authenticateWithWWPass(self, userService, authenticationService, identity, ticket): - puid = self.getPuid(ticket) - user = userService.getUserByAttribute("oxExternalUid", "wwpass:%s"%puid) - if user: - if authenticationService.authenticate(user.getUserId()): - return True - else: - if self.registration_url and self.tryFirstLogin(puid, userService, authenticationService): - return True - identity.setWorkingParameter("puid", puid) - identity.setWorkingParameter("ticket", ticket) - return True - return False - - def bindWWPass(self, requestParameters, userService, authenticationService, identity, ticket): - puid = identity.getWorkingParameter("puid") - email = requestParameters.get('email')[0] if 'email' in requestParameters else None - if not puid: - identity.setWorkingParameter("errors", "WWPass login failed") - return False - if ticket: - puid_new = self.getPuid(ticket) - # Always use the latest PUID when retrying step 2 - identity.setWorkingParameter("puid", puid_new) - if puid == puid_new: - # Registering via external web service - if not self.registration_url: - return False - if self.tryFirstLogin(puid, userService, authenticationService): - identity.setWorkingParameter("puid", None) - return True - else: - if not self.allow_passkey_bind: - return False - # Binding with existing PassKey - user = userService.getUserByAttribute("oxExternalUid", "wwpass:%s"%puid_new) - if user: - if authenticationService.authenticate(user.getUserId()): - userService.addUserAttribute(user.getUserId(), "oxExternalUid", "wwpass:%s"%puid) - identity.setWorkingParameter("puid", None) - return True - identity.setWorkingParameter("errors", "Invalid user") - return False - elif email: - # Binding via email - if not self.allow_email_bind: - return False - email = requestParameters.get('email')[0] if 'email' in requestParameters else None - identity.setWorkingParameter("email", email) - user = userService.getUserByAttribute('mail', email) - if not user: - print("User with email '%s' not found." % email) - return True - nonce = self.generateNonce(33) - mailService = CdiUtil.bean(MailService) - identity.setWorkingParameter("email_nonce", nonce) - identity.setWorkingParameter("email_nonce_exp", str(time() + self.EMAIL_NONCE_EXPIRATION)) - subject = "Bind your WWPass Key" - body = """ -To bind your WWPass Key to your account, copy and paste the following -code into "Email code" field in the login form: -%s -If you haven't requested this operation, you can safely disregard this email. - """ - mailService.sendMail(email, subject, body % nonce) - return True - else: - # Binding via username/password - if not self.allow_password_bind: - return False - puid = identity.getWorkingParameter("puid") - if not puid: - return False - credentials = identity.getCredentials() - user_name = credentials.getUsername() - user_password = credentials.getPassword() - logged_in = False - if (StringHelper.isNotEmptyString(user_name) and StringHelper.isNotEmptyString(user_password)): - try: - logged_in = authenticationService.authenticate(user_name, user_password) - except Exception as e: - print(e) - if not logged_in: - identity.setWorkingParameter("errors", "Invalid username or password") - return False - user = authenticationService.getAuthenticatedUser() - if not user: - identity.setWorkingParameter("errors", "Invalid user") - return False - userService.addUserAttribute(user_name, "oxExternalUid", "wwpass:%s"%puid) - identity.setWorkingParameter("puid", None) - return True - return False - - def checkEmailNonce(self, requestParameters, userService, authenticationService, identity, ticket): - # Verify email nonce - if not self.allow_email_bind: - identity.setWorkingParameter("email", None) - return False - puid = identity.getWorkingParameter("puid") - if not puid: - return False - nonce = requestParameters.get('code')[0] if 'code' in requestParameters else None - email = identity.getWorkingParameter("email") - proper_nonce = identity.getWorkingParameter("email_nonce") - nonce_expiration = float(identity.getWorkingParameter("email_nonce_exp") or 0.0) - if not nonce or not email or not proper_nonce or not nonce_expiration or nonce_expiration < time() or nonce != proper_nonce: - print("WWPass. Wrong email verification code", nonce,email,proper_nonce,nonce_expiration, time()) - identity.setWorkingParameter("email", None) - identity.setWorkingParameter("errors", "Invalid email or verification code") - return False - user = userService.getUserByAttribute('mail', email) - identity.setWorkingParameter("email", None) - if user: - if authenticationService.authenticate(user.getUserId()): - userService.addUserAttribute(user.getUserId(), "oxExternalUid", "wwpass:%s"%identity.getWorkingParameter("puid")) - identity.setWorkingParameter("puid", None) - return True - print("No user") - return False - - - def doAuthenticate(self, step, requestParameters, userService, authenticationService, identity, ticket): - if step == 1: - return self.authenticateWithWWPass(userService, authenticationService, identity, ticket) - elif step == 2: - return self.bindWWPass(requestParameters, userService, authenticationService, identity, ticket) - elif step == 3: - return self.checkEmailNonce(requestParameters, userService, authenticationService, identity, ticket) - else: - return False - - - def authenticate(self, configurationAttributes, requestParameters, step): - print("WWPass. Authenticate for step %d" %step) - authenticationService = CdiUtil.bean(AuthenticationService) - userService = CdiUtil.bean(UserService) - ticket = requestParameters.get('wwp_ticket')[0] if 'wwp_ticket' in requestParameters else None - identity = CdiUtil.bean(Identity) - identity.setWorkingParameter("errors", "") - result = self.doAuthenticate(step, requestParameters, userService, authenticationService, identity, ticket) - if result and self.sso_cookie_tags: - externalContext = CdiUtil.bean(FacesContext).getExternalContext() - for tag in self.sso_cookie_tags: - externalContext.addResponseCookie("sso_magic_%s"%tag, "auth", {"path":"/", "domain":self.sso_cookie_domain, "maxAge": CdiUtil.bean(AppConfiguration).getSessionIdUnusedLifetime()}) - return result - - def prepareForStep(self, configurationAttributes, requestParameters, step): - identity = CdiUtil.bean(Identity) - identity.setWorkingParameter("sessionLifetime",CdiUtil.bean(AppConfiguration).getSessionIdUnauthenticatedUnusedLifetime()) - identity.setWorkingParameter("use_pin", bool(self.use_pin)) - print("PrepareForStep %s" % step) - if (step == 1): - return True - elif (step == 2): - identity.setWorkingParameter("registration_url", self.registration_url) - identity.setWorkingParameter("recovery_url", self.recovery_url) - identity.setWorkingParameter("allow_email_bind", self.allow_email_bind) - identity.setWorkingParameter("allow_password_bind", self.allow_password_bind) - identity.setWorkingParameter("allow_passkey_bind", self.allow_passkey_bind) - print("WWPASS. Errors:%s" % identity.getWorkingParameter("errors")) - return True - elif (step == 3): - return True - return False - - def getExtraParametersForStep(self, configurationAttributes, step): - if step == 3: - return Arrays.asList("puid", "email", "email_nonce", "email_nonce_exp", "sessionLifetime") - return Arrays.asList("puid", "ticket", "use_pin", "errors", "email", "sessionLifetime") - - def getCountAuthenticationSteps(self, configurationAttributes): - identity = CdiUtil.bean(Identity) - if not identity.isSetWorkingParameter("puid"): - return 1 - if not identity.isSetWorkingParameter("email"): - return 2 - return 3 - - def getPageForStep(self, configurationAttributes, step): - if step == 1: - return "/auth/wwpass/wwpass.xhtml" - if step == 2: - return "/auth/wwpass/wwpassbind.xhtml" - return "/auth/wwpass/checkemail.xhtml" - - def logout(self, configurationAttributes, requestParameters): - print("WWPASS. Logout") - # This is not called. Probably bug in Gluu - # externalContext = CdiUtil.bean(FacesContext).getExternalContext() - # externalContext.addResponseCookie("sso_magic", "auth", {"path":"/", "domain":self.sso_cookie_domain, "maxAge": 0}) - return True - - def getNextStep(self, configurationAttributes, requestParameters, step): - # If user did not pass this step, change the step to previous one - identity = CdiUtil.bean(Identity) - puid = identity.getWorkingParameter("puid") - email = identity.getWorkingParameter("email") - print ("WWPass getNextStep for step %d, email: %s" % (step, email)) - if puid and not email and step != 1: - return 2 - return -1