new configuration version

This commit is contained in:
mamo 2024-11-12 13:04:30 +00:00
parent 7df39f92cb
commit ac34686014
70 changed files with 31593 additions and 389 deletions

View File

@ -45,7 +45,7 @@ spec:
podDisruptionBudget:
maxUnavailable: "50%"
git:
tag: "r-37b6dc37f2eba84f437a692943c65922a8674121"
tag: "r-273c80f3ed81849ff45349dd7d23b000a9535c6f"
dir: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT/DEFAULT-ADN-POST-IAM-TKNXCHNG-INV/nai"
credentials: "git-credentials"
keystores:

View File

@ -12,3 +12,5 @@ spec:
keystores:
- name: "npi-cossa-realm-identity"
namespace: "adn-postit-tknxchng-01-dev"
- name: "npi-new-authentication-realm-identity"
namespace: "adn-postit-tknxchng-01-dev"

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE esauth-server SYSTEM "/opt/nevisauth/dtd/esauth4.dtd">
<esauth-server instance="nai">
<!-- source: pattern://6ec6739e824c8e56d9633622, pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://6ec6739e824c8e56d9633622, pattern://8523f0587aa8cfa7008f8171 -->
<SessionCoordinator sessionInitialInactivityTimeout="600" sessionInactivityTimeout="28800" sessionMaxLifetime="28800" sessionIdPreGenerate="true">
<!-- source: pattern://6ec6739e824c8e56d9633622 -->
<LocalSessionStore maxSessions="100000"/>
<!-- source: pattern://6ec6739e824c8e56d9633622 -->
<TokenAssembler name="DefaultTokenAssembler">
<Selector default="true"/>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://b67f81a971e4c08aa79040a2, pattern://8523f0587aa8cfa7008f8171 -->
<TokenSpec ttl="28800">
<!-- source: pattern://6ec6739e824c8e56d9633622 -->
<field src="session" key="ch.nevis.session.sessid" as="sessid"/>
@ -40,36 +40,69 @@
<!-- source: pattern://d9ea344685ab4a9bb0e1e3e7 -->
<KeyStore name="JwtToken">
<!-- source: pattern://d9ea344685ab4a9bb0e1e3e7 -->
<KeyObject name="New_nevisAuth_KeyObject" certificate="/var/opt/keys/own/new-pem-key-store/cert.pem" privateKey="/var/opt/keys/own/new-pem-key-store/keystore.jks" passPhrase="pipe:///var/opt/keys/own/new-pem-key-store/keypass"/>
</KeyStore>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<KeyStore name="Store_New_OAuth_2.0_Authorization_Server_OpenID_Provider">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<KeyObject name="Signer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" certificate="/var/opt/keys/own/new-pem-key-store/cert.pem" privateKey="/var/opt/keys/own/new-pem-key-store/keystore.jks" passPhrase="pipe:///var/opt/keys/own/new-pem-key-store/keypass"/>
<KeyObject name="tokensigner" certificate="/var/opt/keys/own/tokensigner/cert.pem" privateKey="/var/opt/keys/own/tokensigner/keystore.jks" passPhrase="pipe:///var/opt/keys/own/tokensigner/keypass"/>
</KeyStore>
</SessionCoordinator>
<!-- source: pattern://6ec6739e824c8e56d9633622 -->
<LocalOutOfContextDataStore reaperPeriod="60"/>
<!-- source: pattern://6ec6739e824c8e56d9633622, pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://6ec6739e824c8e56d9633622, pattern://8523f0587aa8cfa7008f8171, pattern://6ec6739e824c8e56d9633622 -->
<AuthEngine useLiteralDictionary="true" literalDictionaryLanguages="en,de,fr,it" inputLanguageCookie="LANG" compatLevel="none" addAutheLevelToSecRoles="true" classPath="/var/opt/nevisauth/default/plugin:/opt/nevisauth/plugin" propagateSession="false">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Domain name="New_Authentication_Realm" default="false" inactiveInterval="7200" reauthInterval="0" resetAuthenticationCondition="${inargs:cancel}">
<Entry method="authenticate" state="New_Authentication_Realm_New_JSON_Response_Step"/>
<Entry method="stepup" state="New_Authentication_Realm_Selector"/>
</Domain>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<Domain name="cossa_realm" default="false" inactiveInterval="7200" reauthInterval="0" resetAuthenticationCondition="${inargs:cancel}">
<Entry method="authenticate" state="cossa_realm_TokenExchangeEndpoint"/>
<Entry method="authenticate" state="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" selector="${request:currentResource:^http[s]?\u003A//[^/]+/oauth/authorize($|\?.*)$:true}"/>
<Entry method="authenticate" state="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" selector="${request:currentResource:^http[s]?\u003A//[^/]+/oauth/token($|\?.*)$:true}"/>
<Entry method="authenticate" state="cossa_realm_TokenExchangeEndpoint" selector="${request:currentResource:^http[s]?\u003A//[^/]+/token/.*$:true}"/>
<Entry method="logout" state="cossa_realm_AuthorizationServer"/>
<Entry method="logout" state="cossa_realm_AuthorizationServer" selector="${request:currentResource:^http[s]?\u003A//[^/]+/token/.*$:true}"/>
<Entry method="stepup" state="cossa_realm_Selector"/>
<Entry method="stepup" state="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" selector="${request:currentResource:^http[s]?\u003A//[^/]+/oauth/authorize($|\?.*)$:true}"/>
<Entry method="stepup" state="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" selector="${request:currentResource:^http[s]?\u003A//[^/]+/oauth/token($|\?.*)$:true}"/>
<Entry method="stepup" state="cossa_realm_TokenExchangeEndpoint" selector="${request:currentResource:^http[s]?\u003A//[^/]+/token/.*$:true}"/>
</Domain>
<AuthState name="New_Authentication_Realm_New_JSON_Response_Step" class="ch.nevis.esauth.auth.states.directResponse.DirectResponseState" final="true" resumeState="false">
<!-- source: pattern://3f7b857b6d35114fcd8c4984 -->
<Response value="AUTH_DONE"/>
<!-- source: pattern://3f7b857b6d35114fcd8c4984 -->
<property name="content" value="file:///var/opt/nevisauth/default/conf/new_authentication_realm_new_json_response_step.json"/>
<!-- source: pattern://3f7b857b6d35114fcd8c4984 -->
<property name="contentType" value="application/json"/>
<!-- source: pattern://3f7b857b6d35114fcd8c4984 -->
<property name="statusCode" value="200"/>
</AuthState>
<AuthState name="New_Authentication_Realm_Selector" class="ch.nevis.esauth.auth.states.standard.ConditionalDispatcherState" final="false">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<ResultCond name="nomatch" next="New_Authentication_Realm_Prepare_Done"/>
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Response value="AUTH_ERROR">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Arg name="ch.nevis.isiweb4.response.status" value="403"/>
</Response>
</AuthState>
<AuthState name="New_Authentication_Realm_Prepare_Done" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<ResultCond name="default" next="New_Authentication_Realm_Auth_Done"/>
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Response value="AUTH_DONE">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Gui name="ContinueResponse"/>
</Response>
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<property name="script" value="file:///var/opt/nevisauth/default/conf/prepare_done.groovy"/>
</AuthState>
<AuthState name="New_Authentication_Realm_Auth_Done" class="ch.nevis.esauth.auth.states.standard.AuthDone" final="false">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Response value="AUTH_DONE">
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<Gui name="ContinueResponse"/>
</Response>
</AuthState>
<AuthState name="cossa_realm_TokenExchangeEndpoint" class="ch.adnovum.cossa.TokenExchangeEndpoint" authLevel="auth.weak" final="false" resumeState="true">
<!-- source: pattern://89578db79d2bc15d55e11141 -->
<ResultCond name="failed" next="cossa_realm_New_Authentication_Failed"/>
<ResultCond name="failed" next="cossa_realm_auth_failed"/>
<!-- source: pattern://89578db79d2bc15d55e11141 -->
<ResultCond name="ok" next="cossa_realm_New_Transform_Variables_Step"/>
<ResultCond name="ok" next="cossa_realm_sec_token_prep_prov"/>
<!-- source: pattern://89578db79d2bc15d55e11141 -->
<Response value="AUTH_CONTINUE">
<!-- source: pattern://89578db79d2bc15d55e11141 -->
@ -80,7 +113,7 @@
<!-- source: pattern://89578db79d2bc15d55e11141 -->
<property name="clientSecret" value="clientPassword"/>
</AuthState>
<AuthState name="cossa_realm_New_Authentication_Failed" class="ch.nevis.esauth.auth.states.standard.AuthError" final="false">
<AuthState name="cossa_realm_auth_failed" class="ch.nevis.esauth.auth.states.standard.AuthError" final="false">
<!-- source: pattern://72e29eb80a951e518ce123e4 -->
<Response value="AUTH_ERROR">
<!-- source: pattern://72e29eb80a951e518ce123e4 -->
@ -92,7 +125,7 @@
</Gui>
</Response>
</AuthState>
<AuthState name="cossa_realm_New_Transform_Variables_Step" class="ch.nevis.esauth.auth.states.standard.TransformAttributes" final="false">
<AuthState name="cossa_realm_sec_token_prep_prov" class="ch.nevis.esauth.auth.states.standard.TransformAttributes" final="false">
<!-- source: pattern://32290d5b7c7cdb369674c3a0 -->
<ResultCond name="ok" next="cossa_realm_JwtToken"/>
<!-- source: pattern://32290d5b7c7cdb369674c3a0 -->
@ -123,7 +156,7 @@
</AuthState>
<AuthState name="cossa_realm_Prepare_Done" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false">
<!-- source: pattern://e02a36447ce2d3c66d8d81c0, pattern://b67f81a971e4c08aa79040a2 -->
<ResultCond name="default" next="cossa_realm_02_CheckConsent_New_OAuth_2.0_Authorization_Server_OpenID_Provider"/>
<ResultCond name="default" next="cossa_realm_Auth_Done"/>
<!-- source: pattern://e02a36447ce2d3c66d8d81c0, pattern://b67f81a971e4c08aa79040a2 -->
<Response value="AUTH_DONE">
<!-- source: pattern://e02a36447ce2d3c66d8d81c0, pattern://b67f81a971e4c08aa79040a2 -->
@ -132,37 +165,6 @@
<!-- source: pattern://e02a36447ce2d3c66d8d81c0, pattern://b67f81a971e4c08aa79040a2 -->
<property name="script" value="file:///var/opt/nevisauth/default/conf/prepare_done.groovy"/>
</AuthState>
<AuthState name="cossa_realm_02_CheckConsent_New_OAuth_2.0_Authorization_Server_OpenID_Provider" class="ch.nevis.esauth.auth.states.oauth2.consentstate.ConsentState" final="false">
<ResultCond name="ok" next="cossa_realm_Auth_Done"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="reject" next="cossa_realm_Authentication_Failed"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<Response value="AUTH_CONTINUE">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<Gui name="oauth_consent" label="title.oauth.consent">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="prompt" type="info" label="info.oauth.consent"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="accept" type="button" label="accept.button.label" value="approve"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="reject" type="button" label="reject.button.label" value="deny" optional="false"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="clientName" type="info" label="" value="${notes:client_name}" optional="false"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="clientLogo" type="image" label="" value="${notes:logo_uri}" optional="false"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="clientToS" type="link" label="consent.tos.link.label" value="${notes:tos_uri}" optional="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="clientPolicy" type="link" label="consent.policy.link.label" value="${notes:policy_uri}" optional="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="consentInformation" type="hidden" value="${notes:consentInformation}" optional="true"/>
</Gui>
</Response>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="dataSource" value="nevismeta"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="nevismeta.location" value="https://sdfsdfdf.ch:443/nevismeta/rest/modules/oauthv2/setups/Setup_00000000000000000000000000000000/entities"/>
</AuthState>
<AuthState name="cossa_realm_Auth_Done" class="ch.nevis.esauth.auth.states.standard.AuthDone" final="false">
<!-- source: pattern://e02a36447ce2d3c66d8d81c0, pattern://b67f81a971e4c08aa79040a2 -->
<Response value="AUTH_DONE">
@ -170,123 +172,6 @@
<Gui name="ContinueResponse"/>
</Response>
</AuthState>
<AuthState name="cossa_realm_Authentication_Failed" class="ch.nevis.esauth.auth.states.standard.AuthError" final="false">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<Response value="AUTH_ERROR">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<Gui name="Error">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="info" type="error" label="error_99"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<GuiElem name="submit" type="button" label="continue.button.label"/>
</Gui>
</Response>
</AuthState>
<AuthState name="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider" class="ch.nevis.esauth.auth.states.oauth2.AuthorizationServer" final="false">
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="authenticate:valid-authorization-request" next="cossa_realm_TokenExchangeEndpoint"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="invalid-authorization-request" next="cossa_realm_Authentication_Failed"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="invalid-client" next="cossa_realm_Authentication_Failed"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="invalid-redirect-uri" next="cossa_realm_Authentication_Failed"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="invalid-token-request" next="cossa_realm_Authentication_Failed"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<ResultCond name="stepup:valid-authorization-request" next="cossa_realm_Selector"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="keystoreref" value="Store_New_OAuth_2.0_Authorization_Server_OpenID_Provider"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="keyobjectref" value="Signer_New_OAuth_2.0_Authorization_Server_OpenID_Provider"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="keyID" value="Signer_New_OAuth_2.0_Authorization_Server_OpenID_Provider"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="openid.idTokenLifetime" value="600"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="authCodeLifetime" value="60"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="propagationScope" value="session"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="dataSource" value="nevismeta"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="nevismeta.location" value="https://sdfsdfdf.ch:443/nevismeta/rest/modules/oauthv2/setups/Setup_00000000000000000000000000000000/entities"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="nevismeta.maxAge" value="600"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="openid.support" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="openid.issuerId" value="https://klp.agov-w.azure.adnovum.net"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.openid" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.openid.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.openid.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.openid.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.openid.clientCredentialsFlowPolicy" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.offline_access" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.offline_access.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.offline_access.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.offline_access.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.offline_access.clientCredentialsFlowPolicy" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.address" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.address.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.address.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.address.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.address.clientCredentialsFlowPolicy" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.profile" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.profile.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.profile.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.profile.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.profile.clientCredentialsFlowPolicy" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.email" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.email.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.email.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.email.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.email.clientCredentialsFlowPolicy" value="true"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.phone" value=""/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.phone.authorizationCodeFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.phone.refreshTokenRequestPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.phone.implicitFlowPolicy" value="NO_CONSENT_REQUIRED"/>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<property name="scope.phone.clientCredentialsFlowPolicy" value="true"/>
</AuthState>
<AuthState name="cossa_realm_Selector" class="ch.nevis.esauth.auth.states.standard.ConditionalDispatcherState" final="false">
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<ResultCond name="nomatch" next="cossa_realm_Prepare_Done"/>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<Response value="AUTH_ERROR">
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<Arg name="ch.nevis.isiweb4.response.status" value="403"/>
</Response>
</AuthState>
<AuthState name="cossa_realm_AuthorizationServer" class="ch.nevis.esauth.auth.states.oauth2.AuthorizationServer" final="false" resumeState="true">
<!-- source: pattern://e02a36447ce2d3c66d8d81c0 -->
<ResultCond name="authenticate:valid-authorization-request" next="cossa_realm_Prepare_Done"/>
@ -379,12 +264,16 @@
<!-- source: pattern://e02a36447ce2d3c66d8d81c0 -->
<property name="scope.phone.clientCredentialsFlowPolicy" value="true"/>
</AuthState>
<AuthState name="cossa_realm_Selector" class="ch.nevis.esauth.auth.states.standard.ConditionalDispatcherState" final="false">
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<ResultCond name="nomatch" next="cossa_realm_Prepare_Done"/>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<Response value="AUTH_ERROR">
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<Arg name="ch.nevis.isiweb4.response.status" value="403"/>
</Response>
</AuthState>
</AuthEngine>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<RESTService name="New OAuth 2.0 / OpenID Connect Token Introspection Endpoint" class="ch.nevis.esauth.rest.service.tokenintrospection.TokenIntrospectionService" path="/oauth/introspect">
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<property name="authstates" value="cossa_realm_AuthorizationServer_New_OAuth_2.0_Authorization_Server_OpenID_Provider"/>
</RESTService>
<!-- source: pattern://b0fedec4607e1e69103b8497 -->
<RESTService name="rest" class="ch.nevis.esauth.rest.service.tokenintrospection.TokenIntrospectionService" path="/oauth/introspect2/">
<!-- source: pattern://b0fedec4607e1e69103b8497 -->

View File

@ -22,10 +22,6 @@ Configuration:
level: "FATAL"
- name: "AuthEngine"
level: "INFO"
- name: "OAuth2"
level: "DEBUG"
- name: "REST"
level: "DEBUG"
- name: "Vars"
level: "INFO"
Root:

View File

@ -0,0 +1,41 @@
{
"application": "fakeapp1_b2b_internal",
"profiles": [
{
"profileId": "12047881",
"description": "12047881 - Marco Mojana, Via Pratocarasso 40, 6500 Bellinzona",
"enabled": true,
"role": "PB",
"violatedPolicies": [
],
"currentGtcAccepted": true
},
{
"profileId": "10628414",
"description": "10628414 - TRE CASTELLI FITNESS CENTER SA, Via Canonico Ghiringhelli 18, 6500 Bellinzona",
"enabled": false,
"role": "SA",
"violatedPolicies": [
{
"policyName": "RULE_AUTH_LEVEL"
}
],
"currentGtcAccepted": false
},
{
"profileId": "10650910",
"description": "10650910 - Roberto Rampa",
"enabled": true,
"role": "PB",
"violatedPolicies": [
{
"policyName": "RULE_AUTH_LEVEL"
},
{
"policyName": "RULE_USER_ACCOUNT_TYPE_MATCH_APPLICATION_ACCOUNT_TYPES"
}
],
"currentGtcAccepted": false
}
]
}

View File

@ -44,7 +44,7 @@ spec:
podDisruptionBudget:
maxUnavailable: "50%"
git:
tag: "r-349deb4960bc8a877066f3a6694b305a59b3388b"
tag: "r-273c80f3ed81849ff45349dd7d23b000a9535c6f"
dir: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT/DEFAULT-ADN-POST-IAM-TKNXCHNG-INV/nli"
credentials: "git-credentials"
podSecurity:

View File

@ -0,0 +1,26 @@
# source: pattern://8523f0587aa8cfa7008f8171
application.countries.default=CH
# source: pattern://8523f0587aa8cfa7008f8171
cache.file.exempt=
# source: pattern://8523f0587aa8cfa7008f8171
cache.filefolder.exempt=
# source: pattern://8523f0587aa8cfa7008f8171
application.language.source.1=param:language
# source: pattern://8523f0587aa8cfa7008f8171
application.language.source.2=cookie:LANG
# source: pattern://8523f0587aa8cfa7008f8171
application.language.source.3=gui
# source: pattern://8523f0587aa8cfa7008f8171
application.language.source.4=browser
# source: pattern://8523f0587aa8cfa7008f8171
application.languages=en,de,fr,it
# source: pattern://8523f0587aa8cfa7008f8171
application.languages.default=en
# source: pattern://7dc20659babc66c4401ce0dd
application.language.cookie.en=LANG:en
# source: pattern://7dc20659babc66c4401ce0dd
application.language.cookie.de=LANG:de
# source: pattern://7dc20659babc66c4401ce0dd
application.language.cookie.fr=LANG:fr
# source: pattern://7dc20659babc66c4401ce0dd
application.language.cookie.it=LANG:it

View File

@ -0,0 +1,6 @@
language.de=Deutsch
language.en=English
language.fr=Fran&ccedil;ais
language.it=Italiano
title=NEVIS SSO Portal

View File

@ -0,0 +1,6 @@
language.de=Deutsch
language.en=English
language.fr=Fran&ccedil;ais
language.it=Italiano
title=NEVIS SSO Portal

View File

@ -0,0 +1,6 @@
language.de=Deutsch
language.en=English
language.fr=Fran&ccedil;ais
language.it=Italiano
title=NEVIS SSO Portal

View File

@ -0,0 +1,6 @@
language.de=Deutsch
language.en=English
language.fr=Fran&ccedil;ais
language.it=Italiano
title=NEVIS SSO Portal

View File

@ -0,0 +1,6 @@
language.de=Deutsch
language.en=English
language.fr=Fran&ccedil;ais
language.it=Italiano
title=NEVIS SSO Portal

View File

@ -0,0 +1,165 @@
let baseURL; // base URL
let statusToken; // used to check progress
let dispatcherElement; // to display link or QR code
let infoElement; // to display info text
let errorElement; // to display error text
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
function submitStatus(status) {
// we have to do a form POST instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, "status", status);
document.body.appendChild(form);
form.submit();
}
const Status = {
_pollInterval: 2 * 1000, // Check every 2 seconds
latest: null,
startPolling: function (token, uiCallback) {
let interval = setInterval(async () => {
await this._check(token).then(function (resp) {
console.log("Polling status: %o", resp);
uiCallback && uiCallback(resp, false);
return Status.latest = resp;
})
.catch(function (err) {
console.error("Error during polling: %o", err);
return false;
});
if (Status.latest && (Status.latest.status === 'succeeded' || Status.latest.status === 'failed' || Status.latest.status === 'unknown')) {
// Done!
console.log('Latest status is: %o', this.latest);
uiCallback && uiCallback(this.latest, true);
clearInterval(interval);
}
}, this._pollInterval);
},
_check: async function (token) {
const payload = { statusToken: token };
const response = await fetch(baseURL + 'api/v1/status', {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'omit',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(payload),
redirect: 'follow',
referrerPolicy: 'no-referrer'
});
return await response.json();
}
};
function setDeepLinkLabel(button) {
const text = document.getElementsByName('info.deeplink')[0].value;
button.innerHTML = text;
}
function messageScanQR() {
const text = document.getElementsByName('info.qrcode')[0].value;
infoElement.innerHTML = text;
}
function messageCheckPhone() {
const text = document.getElementsByName('info.check.phone')[0].value;
infoElement.innerHTML = text;
}
const Element = {
_elem: null, // QR code or deep link depending on device
show: function (appLink) {
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
const isIphone = 'iPhone' === navigator.platform;
const isAndroid = /android/i.test(userAgent) && /mobile/i.test(userAgent);
if (isAndroid || isIphone) {
this._elem = document.createElement('a');
this._elem.setAttribute('href', appLink);
this._elem.setAttribute('class', 'btn btn-primary');
this._elem.setAttribute('target', '_blank');
dispatcherElement.appendChild(this._elem);
setDeepLinkLabel(this._elem);
}
else {
const authenticationType = document.getElementsByName('authenticationType')[0].value;
if (authenticationType == 'push') {
messageCheckPhone();
}
else {
messageScanQR();
this._elem = document.createElement('canvas');
dispatcherElement.appendChild(this._elem);
var qrcode = new QRious({
element: this._elem,
foreground: "#168CA9",
level: "M",
size: 280,
value: appLink
});
}
}
},
hide: function() {
// hide the element which was shown
if (this._elem != null) {
this._elem.style.display = "none";
}
}
};
function authenticateUser(appLink) {
Element.show(appLink);
console.log('Starting Authentication Cloud status polling...');
Status.startPolling(statusToken, (st, done) => {
if (st.status === 'succeeded') {
console.log('Authentication Cloud login done.');
submitStatus('succeeded')
}
else if (st.status === 'failed') {
// failed: The transaction failed, either by timeout or because the user did not accept.
console.warn('Authentication Cloud login failed. User abort or timeout.');
submitStatus('failed')
}
else if (st.status === 'unknown') {
console.error('Authentication Cloud login failed. Unknown status.');
submitStatus('unknown')
}
});
}
function init() {
const form = document.getElementById('authcloud_login');
baseURL = form.url.value;
statusToken = form.statusToken.value;
infoElement = document.getElementById('authcloud_info');
errorElement = document.getElementById('authcloud_error');
dispatcherElement = document.getElementById('authcloud_dispatch');
const appLink = form.appLink.value;
authenticateUser(appLink);
}
window.onload = function() {
init();
};

View File

@ -0,0 +1,154 @@
let baseURL; // base URL
let statusToken; // used to check progress
let dispatcherElement; // to display link or QR code
let infoElement; // to display info text
let errorElement; // to display error text
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
function submitStatus(status) {
// we have to do a form POST instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, "status", status);
document.body.appendChild(form);
form.submit();
}
const Status = {
_pollInterval: 2 * 1000, // Check every 2 seconds
latest: null,
startPolling: function (token, uiCallback) {
let interval = setInterval(async () => {
await this._check(token).then(function (resp) {
console.log("Polling status: %o", resp);
uiCallback && uiCallback(resp, false);
return Status.latest = resp;
})
.catch(function (err) {
console.error("Error during polling: %o", err);
return false;
});
if (Status.latest && (Status.latest.status === 'succeeded' || Status.latest.status === 'failed' || Status.latest.status === 'unknown')) {
// Done!
console.log('Latest status is: %o', this.latest);
uiCallback && uiCallback(this.latest, true);
clearInterval(interval);
}
}, this._pollInterval);
},
_check: async function (token) {
const payload = { statusToken: token };
const response = await fetch(baseURL + 'api/v1/status', {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'omit',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(payload),
redirect: 'follow',
referrerPolicy: 'no-referrer'
});
return await response.json();
}
};
function setDeepLinkLabel(button) {
const text = document.getElementsByName('info.deeplink')[0].value;
button.innerHTML = text;
}
function messageScanQR() {
const text = document.getElementsByName('info.qrcode')[0].value;
infoElement.innerHTML = text;
}
const Element = {
_elem: null, // QR code or deep link depending on device
show: function (appLink) {
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
const isIphone = 'iPhone' === navigator.platform;
const isAndroid = /android/i.test(userAgent) && /mobile/i.test(userAgent);
if (isAndroid || isIphone) {
this._elem = document.createElement('a');
this._elem.setAttribute('href', appLink);
this._elem.setAttribute('class', 'btn btn-primary');
this._elem.setAttribute('target', '_blank');
dispatcherElement.appendChild(this._elem);
setDeepLinkLabel(this._elem);
}
else {
messageScanQR();
this._elem = document.createElement('canvas');
dispatcherElement.appendChild(this._elem);
var qrcode = new QRious({
element: this._elem,
foreground: "#168CA9",
level: "M",
size: 280,
value: appLink
});
}
},
hide: function() {
// hide the element which was shown
if (this._elem != null) {
this._elem.style.display = "none";
}
}
};
function onboardUser(appLink) {
Element.show(appLink);
console.log('Starting Authentication Cloud status polling...');
Status.startPolling(statusToken, (st, done) => {
if (st.status === 'succeeded') {
console.log('Authentication Cloud onboarding done.');
submitStatus('succeeded')
}
else if (st.status === 'failed') {
// failed: The transaction failed, either by timeout or because the user did not accept.
console.warn('Authentication Cloud onboarding failed. User abort or timeout.');
submitStatus('failed')
}
else if (st.status === 'unknown') {
console.error('Authentication Cloud onboarding failed. Unknown status.');
submitStatus('unknown')
}
});
}
function init() {
const form = document.getElementById('authcloud_onboard');
baseURL = form.url.value;
statusToken = form.statusToken.value;
infoElement = document.getElementById('authcloud_info');
errorElement = document.getElementById('authcloud_error');
dispatcherElement = document.getElementById('authcloud_dispatch');
const appLink = form.appLink.value;
onboardUser(appLink);
}
window.onload = function() {
init();
};

View File

@ -0,0 +1,87 @@
/*
* Base64URL-ArrayBuffer
* https://github.com/herrjemand/Base64URL-ArrayBuffer
*
* Copyright (c) 2017 Yuriy Ackermann <ackermann.yuriy@gmail.com>
* Copyright (c) 2012 Niklas von Hertzen
* Licensed under the MIT license.
*
*/
(function() {
"use strict";
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
// Use a lookup table to find the index.
var lookup = new Uint8Array(256);
for (var i = 0; i < chars.length; i++) {
lookup[chars.charCodeAt(i)] = i;
}
var encode = function(arraybuffer) {
var bytes = new Uint8Array(arraybuffer),
i, len = bytes.length, base64 = "";
for (i = 0; i < len; i+=3) {
base64 += chars[bytes[i] >> 2];
base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
base64 += chars[bytes[i + 2] & 63];
}
if ((len % 3) === 2) {
base64 = base64.substring(0, base64.length - 1);
} else if (len % 3 === 1) {
base64 = base64.substring(0, base64.length - 2);
}
return base64;
};
var decode = function(base64) {
var bufferLength = base64.length * 0.75,
len = base64.length, i, p = 0,
encoded1, encoded2, encoded3, encoded4;
var arraybuffer = new ArrayBuffer(bufferLength),
bytes = new Uint8Array(arraybuffer);
for (i = 0; i < len; i+=4) {
encoded1 = lookup[base64.charCodeAt(i)];
encoded2 = lookup[base64.charCodeAt(i+1)];
encoded3 = lookup[base64.charCodeAt(i+2)];
encoded4 = lookup[base64.charCodeAt(i+3)];
bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
}
return arraybuffer;
};
/**
* Exporting and stuff
*/
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
module.exports = {
'encode': encode,
'decode': decode
}
} else {
if (typeof define === 'function' && define.amd) {
define([], function() {
return {
'encode': encode,
'decode': decode
}
});
} else {
window.base64url = {
'encode': encode,
'decode': decode
}
}
}
})();

View File

@ -0,0 +1,222 @@
/********************************************************
* Layout
********************************************************/
html { /* magic to position footer */
position: relative;
min-height: 100%;
}
body {
margin-bottom: 76px; /* == footer height */
}
.container, .container-fluid {
padding-left: 36px;
padding-right: 36px;
}
nav {
min-height: 100px;
padding: 36px;
}
header {
margin-bottom: 16px; /* h1.logintitle adds 20px => 36px */
}
.container {
min-width: 260px;
max-width: 700px;
}
h1 {
margin-bottom: 50px;
}
footer {
width: 100%;
position: absolute;
bottom: 0;
padding: 0 36px;
}
img {
width: 100%;
}
/********************************************************
* Header
********************************************************/
header .logo {
/* width: 20%;*/
/*max-width: 600px;*/
max-height: 150px;
width: auto;
}
/********************************************************
* Dropdown
********************************************************/
a.dropdown-toggle {
text-decoration: none;
}
a.dropdown-toggle:hover {
color: #168CA9;
border-bottom: 3px solid #168CA9;
}
.dropdown-menu {
padding: 5px 0;
}
.dropdown-menu li > a {
padding: 6px 28px;
}
.dropdown-menu a > .prefix {
display: inline-block;
min-width: 22px;
margin-right: 28px;
text-align: right;
}
/********************************************************
* Form
********************************************************/
/* Labels should not be bold */
label {
font-weight: normal;
}
/* Make error messages bold */
.has-error .help-block {
font-weight: bold;
}
/* Change button size, by default 116px in width */
.btn {
min-width: 116px;
padding: 3px 12px;
}
/* Disable gradient in buttons, ughhhh */
.btn.btn-primary {
border-color: transparent;
background-image: none;
text-shadow: none;
box-shadow: none;
-webkit-box-shadow: none;
}
.help-block a, .help-block a:visited {
color: #168CA9;
font-weight: bold;
text-decoration: none;
}
.help-block a:hover {
color: #168CA9;
text-decoration: underline;
}
/********************************************************
* Footer
********************************************************/
footer .row {
margin: 36px 0 0 0;
height: 40px;
padding-top: 14px;
line-height: 26px; /* to center text: height - padding-top = 26px */
border-top: 1px solid #168CA9;
}
footer .row > div { /* Fix alignment between border + text on Bootstrap grid */
padding: 0;
}
footer .logo-round-container {
position: relative;
}
footer .logo-round {
position: absolute;
left: 0;
right: 0;
top: -33px; /* found visually with Chrome Dev Tools */
height: 36px;
width: 36px;
border: 1px solid #00868c;
border-radius: 18px;
background: #fff;
padding: 8px;
}
footer .logo-round > img {
display: block;
}
#dispatchTargets {
margin-top: 20px;
}
/********************************************************
* Social login
********************************************************/
.btn.line {
background-color: transparent;
display: block;
width: 100%;
padding: 0;
margin: 1.5em 0 1em;
border: 0.5px solid #ccc;
pointer-events: none;
}
.btn.socialLogin {
background-color: #fff;
border: thin solid #ccc;
color: #000;
font-weight: 600;
position: relative;
margin: 5px;
min-width: 140px;
width: 210px;
border-radius: 8px;
padding: 8px 12px;
text-align: left;
}
.socialLogin img {
width: 1.5em;
height: 108%;
margin-right: 0.5em;
}
.btn.apple img {
width: 1.2em;
}
/********************************************************
* Show password
********************************************************/
.icon-inside {
position: relative;
}
.icon-inside input {
padding-right: calc(0.75rem + 1.25rem + 0.75rem);
}
.icon-inside button {
position: absolute;
right: 0;
top: 0;
margin-top: 0.45rem;
margin-right: 0.45rem;
background: #FFFFFF;
border: #FFFFFF;
}

View File

@ -0,0 +1,36 @@
(function() {
var closeDropdownTimeout;
function closeDropdown(event) {
var dropdowns = document.querySelectorAll('.dropdown');
for (var i = 0; i < dropdowns.length; i++) {
var dropdownMenu = dropdowns[i].querySelector('.dropdown-menu');
if (dropdownMenu.style.display !== 'none' && !dropdowns[i].contains(event.target)) {
dropdownMenu.style.display = 'none';
}
}
// remove event listener till we have a new dropdown menu open
if (document.querySelector('.dropdown-menu:not([style*="display: none"])') === null) {
document.removeEventListener('click', closeDropdown);
}
}
var dropdowns = document.querySelectorAll('.dropdown');
for (var i = 0; i < dropdowns.length; i++) {
var dropdownMenu = dropdowns[i].querySelector('.dropdown-menu');
dropdownMenu.style.display = 'none'; // ensure menu is initially hidden
dropdowns[i].addEventListener('click', function(e) {
// show dropdown menu
var dropdownMenu = this.querySelector('.dropdown-menu');
dropdownMenu.style.display = 'block';
// handle clicking away
clearTimeout(closeDropdownTimeout);
closeDropdownTimeout = setTimeout(function() {
document.addEventListener('click', closeDropdown);
}, 10);
});
}
}());

View File

@ -0,0 +1,98 @@
var e2eenc = function() {
this.encryptForm = function(algoString, formId) {
// TODO: in case of an error we should return false, to prevent the for to be submitted
// or replace the fields with dummy values, just to prevent the the transmission
// of unencrypted values
// create the array of input fields to encrypt (needs to be done before setting the form
// invisible
var fieldsToEncrypt = new Array();
$.each($("form input:visible"), function(index, _inputField) { fieldsToEncrypt.push($(_inputField));});
// hide the form, and display the splash screen
$('#loginform').css('display','none');
$('#e2eeSplashScreen').css('display','block');
// encryption logic
var pubKey = $("input[name='e2eenc.publicKey']").val();
var kemSessionKey = readPublicKeyAndGenerateSessionKey(pubKey)
var iv = forge.random.getBytesSync(16);
keyB64 = forge.util.encode64(kemSessionKey.key);
encapsulationB64 = forge.util.encode64(kemSessionKey.encapsulation);
ivB64 = forge.util.encode64(iv);
//console.log("Encrypting form " + formId + " (" + algoString + ")");
var fields = "";
$.each(fieldsToEncrypt, function(index, _inputField) {
var inputField = $(_inputField);
if (inputField.attr("type") == "text" || inputField.attr("type") == "password") {
//console.log("Encrypting field " + JSON.stringify(inputField));
var plainValue = inputField.val();
var encryptedValueB64 = encrypt(kemSessionKey, iv, plainValue);
//console.log("Setting encrypted value in b64: " + encryptedValueB64);
inputField.val(encryptedValueB64);
if (fields.length > 0) {
fields = fields + ","
}
fields = fields + inputField.attr("name");
}
});
$("input[name='e2eenc.iv']").val(ivB64);
$("input[name='e2eenc.encapsulation']").val(encapsulationB64);
$("input[name='e2eenc.fields']").val(fields);
}
function getRSApublicKey(pem) {
//console.log("PEM: " + pem);
var msg = forge.pem.decode(pem)[0];
//console.log("msg type: " + msg.type);
if(msg.procType && msg.procType.type === 'ENCRYPTED') {
throw new Error('Could not retrieve RSA public key from PEM; PEM is encrypted.');
}
// convert DER to ASN.1 object
var asn1obj = forge.asn1.fromDer(msg.body);
//console.log("ASN.1 obj: " + JSON.stringify(asn1obj))
var pubKey = forge.pki.publicKeyFromAsn1(asn1obj)
//console.log("PubKey: " + JSON.stringify(pubKey))
return pubKey;
}
function generateKEMSessionKey(rsaPublicKey) {
// generate key-derivation-function and initializes it with sha1
var kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
// creates a KEM function based on the key-derivation-function created above
var kem = forge.kem.rsa.create(kdf1);
// generate and encapsulate a 16-byte secret key.
// The secret key is generated using the kdf defined above.
var kemSessionKey = kem.encrypt(rsaPublicKey, 16);
// kemSessionKey has 'encapsulation' (= pub key) and 'key' (= generated secret key)
return kemSessionKey;
}
function readPublicKeyAndGenerateSessionKey(pem) {
var rsaPublicKey = getRSApublicKey(pem);
//console.log("PubKey: " + JSON.stringify(rsaPublicKey))
var kemSessionKey = generateKEMSessionKey(rsaPublicKey);
//console.log("KEM session key: " + JSON.stringify(kemSessionKey))
return kemSessionKey;
}
function encrypt(kemSessionKey, iv, msg) {
var cipher = forge.cipher.createCipher('AES-CBC', kemSessionKey.key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(msg, 'utf-8'));
cipher.finish();
var encrypted = cipher.output.getBytes();
encryptedB64 = forge.util.encode64(encrypted);
return encryptedB64;
}
};

View File

@ -0,0 +1,3 @@
<svg width="22" height="20" viewBox="0 0 22 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 1L5.58916 4.58916M20 19L16.4112 15.4112M12.8749 16.8246C12.2677 16.9398 11.6411 17 11.0005 17C6.52281 17 2.73251 14.0571 1.45825 9.99997C1.80515 8.8955 2.33851 7.87361 3.02143 6.97118M8.87868 7.87868C9.42157 7.33579 10.1716 7 11 7C12.6569 7 14 8.34315 14 10C14 10.8284 13.6642 11.5784 13.1213 12.1213M8.87868 7.87868L13.1213 12.1213M8.87868 7.87868L5.58916 4.58916M13.1213 12.1213L5.58916 4.58916M13.1213 12.1213L16.4112 15.4112M5.58916 4.58916C7.14898 3.58354 9.00656 3 11.0004 3C15.4781 3 19.2684 5.94291 20.5426 10C19.8357 12.2507 18.3545 14.1585 16.4112 15.4112" stroke="#6D7C80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 769 B

View File

@ -0,0 +1,4 @@
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 8C14 9.65685 12.6569 11 11 11C9.34315 11 8 9.65685 8 8C8 6.34315 9.34315 5 11 5C12.6569 5 14 6.34315 14 8Z" stroke="#6D7C80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.45825 7.99997C2.73253 3.94288 6.52281 1 11.0004 1C15.4781 1 19.2684 3.94291 20.5426 8.00004C19.2684 12.0571 15.4781 15 11.0005 15C6.52281 15 2.73251 12.0571 1.45825 7.99997Z" stroke="#6D7C80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 585 B

View File

@ -0,0 +1,61 @@
(function() {
'use strict'
async function assertion(options) {
let credential;
try {
credential = await navigator.credentials.get({ "publicKey": options });
}
// Cancel and timeout can occur besides error
catch (error) {
console.error(`Failed to get WebAuthn credential: ${error}`);
throw error;
}
// as this is the last call we have to do a top-level request instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, "path", "/nevisfido/fido2/assertion/result")
addInput(form, "id", credential.id);
addInput(form, "type", credential.type);
addInput(form, "response.clientDataJSON", base64url.encode(credential.response.clientDataJSON));
addInput(form, "response.authenticatorData", base64url.encode(credential.response.authenticatorData));
addInput(form, "response.signature", base64url.encode(credential.response.signature));
document.body.appendChild(form);
form.submit();
}
function authenticate() {
// WebAuthn feature detection
if (!isWebAuthnSupportedByTheBrowser()) {
cancelFido2();
return;
};
const request = {};
request.path = "/nevisfido/fido2/attestation/options";
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
})
.then(res => res.json())
.then(options => {
options.challenge = base64url.decode(options.challenge);
options.allowCredentials = options.allowCredentials.map((c) => {
c.id = base64url.decode(c.id);
return c;
});
return assertion(options);
}).catch((error) => {
console.error(`Error during FIDO2 authentication: ${error}`);
cancelFido2();
});
}
authenticate();
})();

View File

@ -0,0 +1,175 @@
(function() {
'use strict'
async function authenticate(username, params) {
try {
const { authenticationOptionsEndpoint, authenticationEndpoint, statusServiceEndpoint, userVerification, originalResource, nevisAuthEndpoint } = params;
const { startAuthentication } = SimpleWebAuthnBrowser;
// fetch authentication options from nevisFIDO and save the returned fido2SessionId for later use
const authOptRespJson = await getAuthenticationOptions(username, userVerification, nevisAuthEndpoint);
const fido2SessionId = authOptRespJson.fido2SessionId;
// do the client side authentication using the SimpleWebAuthn JS library
const authRespJson = await startAuthentication(authOptRespJson);
// in case the authentication response does not contain a userHandle (e.g. virtual authenticators used in system tests)
// then we have to obtain it (in our case it is the IDM extId) using the Status Service since at the moment nevisFIDO always expects it
if (!authRespJson.response.userHandle) {
const statusRespJson = await getFido2SessionStatus(fido2SessionId, statusServiceEndpoint);
if (statusRespJson && statusRespJson.userId) {
console.log("adding userHandle: " + statusRespJson.userId);
authRespJson.response.userHandle = btoa(statusRespJson.userId); // add missing userHandle
}
else {
throw new Error('userHandle is missing and could not determine it using the status service');
}
}
else {
console.log("userHandle already set: " + authRespJson.response.userHandle);
}
// send the assertion response created by the authenticator to nevisFIDO
const serverRespJson = await submitAssertion(authRespJson, authenticationEndpoint);
// checking the server response of nevisFIDO
if ((!serverRespJson) || (serverRespJson && serverRespJson.status !== 'ok')) {
let errorMessage = (serverRespJson && serverRespJson.errorMessage) ? serverRespJson.errorMessage : 'unexpected error';
throw new Error('authentication failed: ' + errorMessage);
}
// send a request to nevisAuth with the fido2SessionId in the header to trigger the synchronisation of the
// nevisFIDO and nevisAuth sessions (FIDO2 AuthState -> SyncFido2SessionStatusHandler) to reach AUTH_DONE
await updateNevisAuth(fido2SessionId, nevisAuthEndpoint);
console.log('authentication was successful');
console.log('reloading page...');
window.location.reload();
}
catch (error) {
console.error(`Error during FIDO2 authentication: ${error}`);
cancelFido2();
}
};
async function getAuthenticationOptions(username, userVerification, authenticationOptionsEndpoint) {
const authOptReqJson = {
'username': username,
'userVerification': userVerification,
};
const authOptReq = JSON.stringify(authOptReqJson);
console.log('authOptReq ==> ' + authOptReq);
const authOptResp = await fetch(authenticationOptionsEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: authOptReq,
});
if (!authOptResp.ok) {
throw new Error('authOptResp error: HTTP ' + authOptResp.status + ' ' + authOptResp.statusText);
}
const authOptRespJson = await authOptResp.json()
console.log('authOptResp <== ' + JSON.stringify(authOptRespJson));
return authOptRespJson;
};
async function getFido2SessionStatus(fido2SessionId, statusServiceEndpoint) {
const statusReqJson = {
'fido2SessionId': fido2SessionId,
};
const statusReq = JSON.stringify(statusReqJson);
console.log('statusReq ==> ' + statusReq);
const statusResp = await fetch(statusServiceEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: statusReq,
});
if (!statusResp.ok) {
throw new Error('statusResp error: HTTP ' + statusResp.status + ' ' + statusResp.statusText);
}
const statusRespJson = await statusResp.json();
console.log('statusResp <== ' + JSON.stringify(statusRespJson));
return statusRespJson;
}
async function submitAssertion(authRespJson, authenticationEndpoint) {
console.log("submitting assertion for userHandle: " + authRespJson.response.userHandle);
// TODO koenig 20230504: read btoa once nevisFIDO is adapted
let encodedAuthResp = {
"id": authRespJson.id,
"response": {
"authenticatorData": authRespJson.response.authenticatorData,
"signature": authRespJson.response.signature,
"userHandle": authRespJson.response.userHandle,
"clientDataJSON": authRespJson.response.clientDataJSON
},
"type": authRespJson.type
}
const authResp = JSON.stringify(encodedAuthResp);
console.log('authResp ==> ' + authResp);
const serverResp = await fetch(authenticationEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: authResp,
});
if (!serverResp.ok) {
throw new Error('submitAssertion error: HTTP ' + submitAssertion.status + ' ' + submitAssertion.statusText);
}
const serverRespJson = await serverResp.json();
console.log('serverResp <== ' + JSON.stringify(serverRespJson));
return serverRespJson;
};
async function updateNevisAuth(fido2SessionId, nevisAuthEndpoint) {
console.log('updateNevisAuth ==> ' + fido2SessionId);
const updateNevisAuthResponse = await fetch(nevisAuthEndpoint, {
method: 'GET',
credentials: 'same-origin',
headers: {
'nevis-fido2-session-id': fido2SessionId,
}
});
if (!updateNevisAuthResponse.ok) {
throw new Error('updateNevisAuthResponse error: HTTP ' + updateNevisAuthResponse.status + ' ' + updateNevisAuthResponse.statusText);
}
console.log('updateNevisAuth <== OK');
return;
};
// TODO koenig 20230206: we don't generate IDs into the HTML yet
let username = document.getElementsByName("username")[0].value;
params.nevisAuthEndpoint = window.location.href;
authenticate(username, params);
})();

View File

@ -0,0 +1,70 @@
function dispatch(name) {
// we have to do a top-level request instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, name, "true");
document.body.appendChild(form);
form.submit();
}
async function attestation(options) {
let credential;
try {
credential = await navigator.credentials.create({ "publicKey": options });
}
// cancel and timeout can occur besides error
catch (error) {
console.error(`Failed to create WebAuthn credential: ${error}`);
throw error;
}
// as this is the last call we have to do a top-level request instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, "path", "/nevisfido/fido2/attestation/result")
addInput(form, "id", credential.id);
addInput(form, "type", credential.type);
addInput(form, "response.clientDataJSON", base64url.encode(credential.response.clientDataJSON));
addInput(form, "response.attestationObject", base64url.encode(credential.response.attestationObject));
document.body.appendChild(form);
form.submit();
}
function start() {
if (!isWebAuthnSupportedByTheBrowser()) {
dispatch("unsupported");
return;
};
const request = {};
request.path = "/nevisfido/fido2/attestation/options";
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
})
.then(res => res.json())
.then(options => {
options.user.id = base64url.decode(options.user.id);
options.challenge = base64url.decode(options.challenge);
if (options.excludeCredentials != null) {
options.excludeCredentials = options.excludeCredentials.map((c) => {
c.id = base64url.decode(c.id);
return c;
});
}
if (options.authenticatorSelection.authenticatorAttachment === null) {
options.authenticatorSelection.authenticatorAttachment = undefined;
}
return attestation(options);
}).catch((error) => {
console.log('Error during FIDO2 onboarding: ' + error);
dispatch("failed");
});
}

View File

@ -0,0 +1,40 @@
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
/**
* Checks whether WebAuthn is supported by the browser or not.
* @return true if supported, false if it is not supported or not in secure context
*/
function isWebAuthnSupportedByTheBrowser() {
if (window.isSecureContext) {
// This feature is available only in secure contexts in some or all supporting browsers.
if ('credentials' in navigator) {
return true;
}
console.warn('Oh no! This browser does not support WebAuthn.');
return false;
}
console.warn('WebAuthn feature is available only in secure contexts. For testing over HTTP, you can use the origin "localhost".');
return false;
}
/**
* Trigger on cancel pattern of the FIDO2 authentication step.
*
* Provides an alternative when the user decides to
* cancel the fido2 credential operation(create or fetch) or
* the operation fails and the error cannot be handled.
*/
function cancelFido2() {
// we have to do a top-level request instead of AJAX
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
addInput(form, "cancel_fido2", "true");
document.body.appendChild(form);
form.submit();
}

View File

@ -0,0 +1 @@
<svg width="842" height="1e3" xmlns="http://www.w3.org/2000/svg"><path d="M702 960c-54.2 52.6-114 44.4-171 19.6-60.6-25.3-116-26.9-180 0-79.7 34.4-122 24.4-170-19.6-271-279-231-704 77-720 74.7 4 127 41.3 171 44.4 65.4-13.3 128-51.4 198-46.4 84.1 6.8 147 40 189 99.7-173 104-132 332 26.9 396-31.8 83.5-72.6 166-141 227zM423 237C414.9 113 515.4 11 631 1c15.9 143-130 250-208 236z"/></svg>

After

Width:  |  Height:  |  Size: 386 B

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1, 0, 0, 1, 27.009001, -39.238998)">
<path fill="#4285F4" d="M -3.264 51.509 C -3.264 50.719 -3.334 49.969 -3.454 49.239 L -14.754 49.239 L -14.754 53.749 L -8.284 53.749 C -8.574 55.229 -9.424 56.479 -10.684 57.329 L -10.684 60.329 L -6.824 60.329 C -4.564 58.239 -3.264 55.159 -3.264 51.509 Z"/>
<path fill="#34A853" d="M -14.754 63.239 C -11.514 63.239 -8.804 62.159 -6.824 60.329 L -10.684 57.329 C -11.764 58.049 -13.134 58.489 -14.754 58.489 C -17.884 58.489 -20.534 56.379 -21.484 53.529 L -25.464 53.529 L -25.464 56.619 C -23.494 60.539 -19.444 63.239 -14.754 63.239 Z"/>
<path fill="#FBBC05" d="M -21.484 53.529 C -21.734 52.809 -21.864 52.039 -21.864 51.239 C -21.864 50.439 -21.724 49.669 -21.484 48.949 L -21.484 45.859 L -25.464 45.859 C -26.284 47.479 -26.754 49.299 -26.754 51.239 C -26.754 53.179 -26.284 54.999 -25.464 56.619 L -21.484 53.529 Z"/>
<path fill="#EA4335" d="M -14.754 43.989 C -12.984 43.989 -11.404 44.599 -10.154 45.789 L -6.734 42.369 C -8.804 40.429 -11.514 39.239 -14.754 39.239 C -19.444 39.239 -23.494 41.939 -25.464 45.859 L -21.484 48.949 C -20.534 46.099 -17.884 43.989 -14.754 43.989 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-label="Microsoft" role="img" viewBox="0 0 512 512"><rect width="512" height="512" rx="15%" fill="#fff"/><path d="M75 75v171h171v-171z" fill="#f25022"/><path d="M266 75v171h171v-171z" fill="#7fba00"/><path d="M75 266v171h171v-171z" fill="#00a4ef"/><path d="M266 266v171h171v-171z" fill="#ffb900"/></svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1,31 @@
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="8.042%" y1="0%" x2="65.682%" y2="23.865%" id="a">
<stop stop-color="#168CA9" stop-opacity="0" offset="0%"/>
<stop stop-color="#168CA9" stop-opacity=".631" offset="63.146%"/>
<stop stop-color="#168CA9" offset="100%"/>
</linearGradient>
</defs>
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)">
<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke="url(#a)" stroke-width="2">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="0.9s"
repeatCount="indefinite" />
</path>
<circle fill="#fff" cx="36" cy="18" r="1">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="0.9s"
repeatCount="indefinite" />
</circle>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,119 @@
(function () {
function createForm() {
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
return form;
}
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
let statusPolling;
function dispatchLink() {
document.getElementById("mauth_started").style.display = "block"; // show
const request = {};
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
// example response: {"dispatchResult":"..."}
if (o.dispatchResult == 'dispatched') {
// example response: {..., "dispatcherInformation":{..., "response":"admin4testing://authenticate?dispatchTokenResponse=ey..."}}
var link = o.dispatcherInformation.response;
console.log("received link: " + link);
var linkElem = document.getElementById("mauth_link");
linkElem.href = link; // custom scheme link does not work in Android 13
const isMobile = !!/(iPhone|iPad|Android)/.test(window.navigator.userAgent);
if (isMobile) {
document.getElementById("mauth_link_parent").style.display = "inline"; // show
}
var url = new URL(link);
var dispatchTokenResponse = url.searchParams.get("dispatchTokenResponse");
// render QR code
var qrCodeElem = document.getElementById("mauth_qrcode");
var qrcode = new QRious({
element: qrCodeElem,
foreground: "#168CA9",
level: "M",
size: 256,
value: link
});
var sessionId = o.sessionId;
console.log("started polling for session ID: " + sessionId);
statusPolling = window.setInterval(function () {
poll(sessionId);
}, 2000);
}
else {
console.log("authentication failed: " + o.dispatchResult);
const form = createForm();
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
function poll(sessionId) {
const request = {};
request.fidoUafSessionId = sessionId;
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
var status = o.status;
console.log("status: " + status);
if (status == 'clientAuthenticating') {
// show process icon
document.getElementById("mauth_loading").style.display = 'block';
// hide QR-code and information
document.getElementById("mauth_qrcode").style.display = 'none';
document.getElementById("mauth_qrcode_info").style.display = 'none';
}
if (status == 'succeeded') {
clearInterval(statusPolling);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
addInput(form, "continue", "true"); // required for custom dispatching in usernameless
document.body.appendChild(form);
form.submit();
}
else if (status == 'failed' || status == 'unknown') {
clearInterval(statusPolling);
console.error("authentication failed with status: " + status);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
addInput(form, "fidoUafSessionId", sessionId);
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
dispatchLink();
})();

View File

@ -0,0 +1,106 @@
(function () {
function createForm() {
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
return form;
}
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
let statusPolling;
function renderEnrollment() {
// link is provided by a hidden GuiElem
var link = document.getElementsByName("mauth_dispatcher_link")[0].value;
console.log("received dispatcher link: " + link);
const isMobile = !!/(iPhone|iPad|Android)/.test(window.navigator.userAgent);
if (isMobile) {
var linkElem = document.getElementById("mauth_link");
linkElem.href = link;
document.getElementById("mauth_link_parent").style.display = "inline"; // show
}
var url = new URL(link);
var dispatchTokenResponse = url.searchParams.get("dispatchTokenResponse");
// render QR code into mauth_qrcode element
var qrCodeElem = document.getElementById("mauth_qrcode");
var qrcode = new QRious({
element: qrCodeElem,
foreground: "#168CA9",
level: "M",
size: 256,
value: link
});
// show entire element
document.getElementById("mauth_started").style.display = "block";
console.log("scheduling status polling (2s interval)");
statusPolling = window.setInterval(function () {
poll();
}, 2000);
}
function poll() {
// state is held on backend side
const request = {};
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
var status = o.status;
console.log("status: " + status);
if (status == 'clientRegistering') {
// show process icon
document.getElementById("mauth_loading").style.display = 'block';
// hide QR-code and information
document.getElementById("mauth_qrcode").style.display = 'none';
document.getElementById("mauth_qrcode_info").style.display = 'none';
}
else if (status == 'succeeded') {
clearInterval(statusPolling);
console.error("onboarding successful");
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
document.body.appendChild(form);
form.submit();
}
else if (status == 'failed' || status == 'unknown') {
clearInterval(statusPolling);
console.error("onboarding failed with status: " + status);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
renderEnrollment();
})();

View File

@ -0,0 +1,172 @@
(function () {
function createForm() {
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
return form;
}
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
let statusPolling;
function dispatch(id) {
document.getElementById("mauth_devices").style.display = "none"; // hide selection menu
document.getElementById("mauth_started").style.display = "block"; // show
const request = {};
request.dispatchTargetId = id;
request.dispatcher = "firebase-cloud-messaging";
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
console.log("dispatch response: " + JSON.stringify(o));
// example response: {"dispatchResult":"..."}
if (o.dispatchResult == 'dispatched') {
// example response: {"token":"...","sessionId":"...","dispatchResult":"dispatched","dispatcherInformation":{"name":"firebase-cloud-messaging","response":"..."}}
console.log("push dispatching successful");
// set numbers for number matching
if (o.channelLinking) {
document.getElementById('mauth_match_numbers').innerHTML = o.channelLinking.content;
}
// preparing content for QR-code
var token = o.token;
console.log("found token: " + token);
// hidden GuiElem
var redeemUrl = document.querySelector('input[name=redeem_url]').value;
console.log("found redeem URL: " + redeemUrl);
let qrCodeContents = {
nma_data_version: "1",
nma_data_content_type: "application/json",
nma_data: {
token: token,
redeem_url: redeemUrl
}
};
var qrCodeValue = window.btoa(JSON.stringify(qrCodeContents));
// render QR code
var qrCodeElem = document.getElementById("mauth_qrcode");
console.log("rendering QR code");
var qrcode = new QRious({
element: qrCodeElem,
foreground: "#168CA9",
level: "M",
size: 256,
value: qrCodeValue
});
var sessionId = o.sessionId;
console.log("started polling for session ID: " + sessionId);
statusPolling = window.setInterval(function () {
poll(sessionId);
}, 2000);
}
else {
console.log("authentication failed: " + o.dispatchResult);
const form = createForm();
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
function renderDeviceList() {
const request = {};
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
// example response: {"dispatchTargets":[{"id":"40a41ac7-0189-4c0b-8db9-cafcaa3e3f11","name":"Android Google Pixel 4 23.11.2022 07:26:25"}]}
var devices = o.dispatchTargets;
if (devices.length > 1) {
console.log("multiple devices found, selection menu required.");
let list = document.getElementById("mauth_devices");
for (let i = 0; i < devices.length; i++) {
let device = devices[i];
var item = document.createElement("li");
item.class = "list-group-item list-group-item-action";
item.onclick = function() { dispatch(device.id) };
item.innerHTML += device.name;
list.appendChild(item);
}
list.style.display = "block"; // show selection menu
}
else if (devices.length == 1) {
console.log("user has only 1 device, no selection required.");
dispatch(devices[0].id);
}
else {
console.error("user has no device.");
// TODO koenig 20221124: design this case
}
});
}).catch((err) => console.error("error: ", err));
}
function poll(sessionId) {
const request = {};
request.fidoUafSessionId = sessionId;
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
var status = o.status;
console.log("status: " + status);
if (status == 'clientAuthenticating') {
document.getElementById("mauth_qrcode").style.display = 'none';
document.getElementById("mauth_qrcode_info").style.display = 'none';
document.getElementById("mauth_match_numbers").style.display = 'block';
document.getElementById("mauth_loading").style.display = 'block';
}
if (status == 'succeeded') {
clearInterval(statusPolling);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
document.body.appendChild(form);
form.submit();
}
else if (status == 'failed' || status == 'unknown') {
clearInterval(statusPolling);
console.error("authentication failed with status: " + status);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
addInput(form, "fidoUafSessionId", sessionId);
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
renderDeviceList();
})();

View File

@ -0,0 +1,119 @@
(function () {
function createForm() {
const form = document.createElement("form");
form.method = "POST";
form.style.display = "none";
return form;
}
function addInput(form, name, value) {
const input = document.createElement("input");
input.name = name;
input.value = value;
form.appendChild(input);
}
let statusPolling;
function dispatch() {
console.log("initiating usernameless mobile authentication...");
document.getElementById("mauth_started").style.display = "block"; // show
const request = {};
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
console.log(o);
// example response: {"dispatchResult":"..."}
if (o.dispatchResult == 'dispatched') {
// example response: {..., "dispatcherInformation":{..., "response":"admin4testing://authenticate?dispatchTokenResponse=ey..."}}
var link = o.dispatcherInformation.response;
console.log("received link: " + link);
var linkElem = document.getElementById("mauth_link");
linkElem.href = link; // custom scheme link does not work in Android 13
const isMobile = !!/(iPhone|iPad|Android)/.test(window.navigator.userAgent);
if (isMobile) {
document.getElementById("mauth_link_parent").style.display = "inline"; // show
}
var url = new URL(link);
var dispatchTokenResponse = url.searchParams.get("dispatchTokenResponse");
// render QR code
var qrCodeElem = document.getElementById("mauth_qrcode");
var qrcode = new QRious({
element: qrCodeElem,
foreground: "#168CA9",
level: "M",
size: 256,
value: link
});
var sessionId = o.sessionId;
console.log("started polling for session ID: " + sessionId);
statusPolling = window.setInterval(function () {
poll(sessionId);
}, 2000);
}
else {
console.log("authentication failed: " + o.dispatchResult);
const form = createForm();
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
function poll(sessionId) {
const request = {};
request.fidoUafSessionId = sessionId;
// calling nevisFIDO through nevisAuth on current URL using AJAX
fetch("", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
}).then(res => {
res.json().then(o => {
var status = o.status;
console.log("status: " + status);
if (status == 'clientAuthenticating') {
document.getElementById("mauth_qrcode").style.display = 'none';
document.getElementById("mauth_loading").style.display = 'block';
}
if (status == 'succeeded') {
clearInterval(statusPolling);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
addInput(form, "fidoUafDone", "true"); // checked by Groovy script
document.body.appendChild(form);
form.submit();
}
else if (status == 'failed' || status == 'unknown') {
clearInterval(statusPolling);
console.error("authentication failed with status: " + status);
// as this is the last call we have to do a top-level request instead of AJAX
const form = createForm();
addInput(form, "fidoUafSessionId", sessionId); // checked by Groovy script
document.body.appendChild(form);
form.submit();
}
});
}).catch((err) => console.error("error: ", err));
}
dispatch();
})();

View File

@ -0,0 +1,43 @@
// display oauth scopes listed in input field 'consentInformation'
// change 'consentInformation' and 'scope_name' to the values used in your configuration.
$(function() {
var consentInformationFieldName = "consentInformation"; // name of the input field from which to parse the value as the consent information JSON
var scopeDescriptionSource = "scope_name"; // key of the field in the consent information JSON of which to get the value as the scope description
function displayOAuthScopesConsent() {
var jsonData = parseJson();
if (jsonData !== undefined) {
mapJsonToHtml(jsonData)
}
}
function mapJsonToHtml(jsonData) {
mapJsonToHtmlScopeList("listOfRequestedScopesWithExistingConsent", jsonData.requestedScopesWithExistingConsent, "Already accepted scopes:");
mapJsonToHtmlScopeList("listOfRequestedScopes", jsonData.requestedScopesRequiringConsent, "Requested scopes that require a consent:");
}
function mapJsonToHtmlScopeList(elementId, scopeInformation, title) {
if (scopeInformation !== undefined && Object.keys(scopeInformation).length > 0) {
$("input[name=" + consentInformationFieldName +"]").after("<p style='margin-top: 0.5em'>" + title + "</p><div class='scopeinfobox'><ul id='" + elementId + "' /> </div>");
jQuery.each(scopeInformation, function(key,value) {
var scopeDescription = value[scopeDescriptionSource];
if (scopeDescription) {
$("#" + elementId).append('<li>' + scopeDescription + '</li>');
} else {
$("#" + elementId).append('<li>' + key + '</li>');
}
});
}
}
function parseJson() {
var consentInformationField = $("input[name=" +consentInformationFieldName +"]");
if (consentInformationField.length > 0) {
return JSON.parse(consentInformationField.val());
}
}
displayOAuthScopesConsent();
});

View File

@ -0,0 +1,11 @@
function toggleInputType(passwordInputId, eyeIconId, resourcePath) {
const passwordInput = document.getElementById(passwordInputId);
const eyeIcon = document.getElementById(eyeIconId);
if (passwordInput.type === 'text') {
passwordInput.type = 'password';
eyeIcon.src = resourcePath + '/resources/eye.svg';
return;
}
passwordInput.type = 'text';
eyeIcon.src = resourcePath + '/resources/eye-off.svg';
}

View File

@ -0,0 +1,65 @@
#set($jsValidation = 1) ## enable JS validation, client-side
#set($useFormEncryption = $gui.encryption && ($gui.encryption.length() > 0))
#set($encryptionParamsOk = true)
#if ($useFormEncryption)
#* check the mandatory e2eenc.publicKey GuiElem *#
#set($encryptionParamsOk = $gui.getGuiElem("e2eenc.publicKey") && ($gui.getGuiElem("e2eenc.publicKey") != "" ))
#end
#if (!$encryptionParamsOk)
$response.setStatus(502)
#else
#set($isAjaxRequest = "XMLHttpRequest" == $login.requestHeaders.get("X-Requested-With"))
#set($acceptHeader = $login.requestHeaders.accept)
#if (!$acceptHeader)
#set($acceptHeader = $login.requestHeaders.Accept)
#end
#if ($acceptHeader)
#set($isHtmlRequest = $acceptHeader.contains("text/html") || $acceptHeader.contains("*/*"))
#set($isJsonRequest = $acceptHeader.contains("application/json"))
#set($isSoapRequest = $acceptHeader.contains("application/soap+xml"))
#set($isXmlRequest = $acceptHeader.contains("application/xml")||$acceptHeader.contains("text/xml"))
#set($isCssRequest = $acceptHeader.contains("text/css"))
#else
#set($isHtmlRequest = true)
#set($isSoapRequest = false)
#set($isXmlRequest = false)
#set($isCssRequest = false)
#end
## sending the query parameter render=form will render only the inner form
#set($isFormRequest = "form" == $login.requestParameters.render && $isHtmlRequest)
#parse("${templatePath}/macros.vm")
#if ($isHtmlRequest)
#if ($isFormRequest)
#parse("${templatePath}/form.vm")
#else
## html.vm is generated from html provided via pattern
#parse("${templatePath}/html.vm")
#end
#end
## AJAX requests: signal to JS-Client that login is required
#if ($isAjaxRequest)
$response.setStatus(401)
$response.setHeader("WWW-Authenticate","$gui.domain")
#end
#if (!$isHtmlRequest && $isXmlRequest)
$response.setHeader("Content-Type","text/xml")
## emit custom XML here, use $utils.escapeXml to sanitize values coming from clients
#end
#if (!$isHtmlRequest && $isJsonRequest)
$response.setHeader("Content-Type","application/json")
#parse("${templatePath}/json.vm")
## emit custom JSON here, use $utils.escapeJs to sanitize values coming from clients
#end
#end

View File

@ -0,0 +1,11 @@
<footer id="footer" class="text-primary">
<div class="row small">
<div class="col-md-4 hidden-xs hidden-sm">Copyright &#169; 2023 NEVIS Security AG</div>
<div class="col-xs-12 col-md-4 text-center text-uppercase logo-round-container">
<div class="logo-round center-block">
<img src="${login.appDataPath}/resources/logo.png" alt="NEVIS Security Suite">
</div>
<strong>NEVIS Security Suite</strong>
</div>
</div>
</footer>

View File

@ -0,0 +1,127 @@
## if only form, then we include javascript here (start of body)
#if ($isFormRequest)
#parse("${templatePath}/js_start.vm")
#end
#set ($formTarget = $utils.escapeHtmlAttribute($gui.target.replaceAll('&?language=[^&]*','')))
#if ($useFormEncryption)
<div id="e2eeSplashScreen" style="display:none;">
<h2 class="logintitle text-center">$gui.label</h2>
<div class="field info" id="info">$text.get("e2ee.splashscreen.msg")</div>
</div>
#end
<div id="loginform">
<form id="$gui.name" name="$gui.name"
#if ($useFormEncryption) onsubmit="new e2eenc().encryptForm('$gui.encryption','$gui.name')" #end
method="POST" target="_self" action="$formTarget" autocomplete="off" accept-charset="UTF-8" class="form-horizontal">
<h1 class="logintitle text-center">$gui.label</h1>
#set ($tabindex = 0)
#set ($policyFailureOpen = false)
#set ($policyInfoOpen = false)
#foreach ($guiElem in $gui.getGuiElems())
#set ($tabindex = $tabindex+1)
#if ($guiElem.name.startsWith("policyInfo") && $guiElem.label && $guiElem.label.length() > 0)
#if (!$policyInfoOpen)
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
#set ($policyInfoOpen = true)
#end
<span class="help-block small" id="$guiElem.name">$guiElem.label</span>
#elseif ($guiElem.name.startsWith("policyFailure") && $guiElem.label && $guiElem.label.length() > 0)
#if (!$policyFailureOpen)
<div class="form-group has-error">
<div class="col-sm-offset-3 col-sm-6">
#set ($policyFailureOpen = true)
#end
<span class="help-block small" id="$guiElem.name">$guiElem.label</span>
#else
#if (!$guiElem.name.startsWith("policyInfo") && $policyInfoOpen) ## close
</div>
</div>
#set ($policyInfoOpen = false)
#end
#if (!$guiElem.name.startsWith("policyFailure") && $policyFailureOpen) ## close
</div>
</div>
#set ($policyFailureOpen = false)
#end
#renderFormField($guiElem, $gui, $tabindex)
#end
#end
## this block applies when Channel is set to Push / Link
#if ($gui.name == "mauth_link_qr" || $gui.name == "mauth_onboard")
<!-- shown after dispatching -->
<center id="mauth_started">
<img id="mauth_loading" style="width: 60px; height: 60px; display: none;" src="${login.appDataPath}/resources/loading.svg"/>
<br><br>
<p id="mauth_qrcode_info">$text.get("mobile_auth.scan")</p>
<canvas id="mauth_qrcode" style="width: 256px; height: 256px;">
</canvas>
<div id="mauth_link_parent" class="form-group" style="display: none">
$text.get("mobile_auth.link")
</div>
</center>
#end
## this block applies when Channel is set to Push / QR-code (in-app)
#if ($gui.name == "mauth_push_qr")
<!-- shown if the user has multiple devices -->
<ul id="mauth_devices" style="display: none">
</ul>
<!-- shown after selecting the device -->
<center id="mauth_started" style="display: none">
<img id="mauth_loading" style="width: 60px; height: 60px; display: none;" src="${login.appDataPath}/resources/loading.svg"/>
<p id="mauth_match_numbers" style="font-size: 64px; display: none;"></p>
<p id="mauth_qrcode_info">$text.get("mobile_auth.push-or-scan")</p>
<canvas id="mauth_qrcode" style="width: 256px; height: 256px;">
</canvas>
</center>
#end
## this block applies for usernameless mobile authentication
#if ($gui.name == "mauth_usernameless")
<center id="mauth_started" style="display: none">
<img id="mauth_loading" style="width: 60px; height: 60px; display: none;" src="${login.appDataPath}/resources/loading.svg"/>
<br><br>
<p id="mauth_qrcode_info">$text.get("mobile_auth.scan")</p>
<canvas id="mauth_qrcode" style="width: 256px; height: 256px;">
</canvas>
<div id="mauth_link_parent" class="form-group" style="display: none">
<a href="" id="mauth_link">$text.get("mobile_auth.link")</a>
</div>
</center>
#end
#if ($useFormEncryption)
<input type="hidden" name="e2eenc.fields" value="not-set">
<input type="hidden" name="e2eenc.iv" value="not-set">
<input type="hidden" name="e2eenc.encapsulation" value="not-set">
#end
#renderFormControls($gui)
#renderFormLinks($gui)
</form>
<!-- position input focus into first element of form -->
<script type="text/javascript">
const form = document.forms['$gui.name'];
if (form) {
const input = form.elements[0];
if (input) {
input.focus();
}
}
</script>
## if only form, then we include javascript here (end of body)
#if ($isFormRequest)
#parse("${templatePath}/js_end.vm")
#end
</div>

View File

@ -0,0 +1,3 @@
<header id="header" class="container-fluid">
<img class="logo center-block" src="${login.appDataPath}/resources/logo_animated.gif" alt="NEVIS Security Suite">
</header>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="${utils.escapeHtml($login.localeCode)}">
<head>
<title>$text.get('title')</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="${login.appDataPath}/resources/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="${login.appDataPath}/resources/bootstrap-theme.min.css" rel="stylesheet" type="text/css" media="all">
<link href="${login.appDataPath}/resources/default.css" rel="stylesheet" type="text/css" media="all">
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
#parse("${templatePath}/js_start.vm")
</head>
<body>
#parse("${templatePath}/lang.vm")
#parse("${templatePath}/header.vm")
<main id="content" class="container">
#parse("${templatePath}/form.vm")
</main>
#parse("${templatePath}/footer.vm")
#parse("${templatePath}/js_end.vm")
</body>
</html>

View File

@ -0,0 +1,76 @@
<script src="${login.appDataPath}/resources/dropdown.js"></script>
<script src="${login.appDataPath}/resources/show-password.js"></script>
#if ($gui.name == "oauth_consent")
<script src="${login.appDataPath}/resources/oauth_consent.js"></script>
#end
#if ($gui.name == "authcloud")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/authcloud.js"></script>
#end
#if ($gui.name == "authcloud_onboard")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/authcloud_onboard.js"></script>
#end
#if ($gui.name == "authcloud_login")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/authcloud_login.js"></script>
#end
#if ($gui.name == "mauth_onboard")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/mauth_onboard.js"></script>
#end
#if ($gui.name == "mauth_link_qr")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/mauth_link_qr.js"></script>
#end
#if ($gui.name == "mauth_push_qr")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/mauth_push_qr.js"></script>
#end
#if ($gui.name == "mauth_usernameless")
<script src="${login.appDataPath}/resources/qrious.min.js"></script>
<script src="${login.appDataPath}/resources/mauth_usernameless.js"></script>
#end
#if ($gui.name == "fido2_auth")
<script src="${login.appDataPath}/resources/base64.js"></script>
<script src="${login.appDataPath}/resources/fido2_utils.js"></script>
<script src="${login.appDataPath}/resources/fido2_auth.js"></script>
#end
#if ($gui.name == "fido2_auth_std")
#set ($authenticationOptionsPath = $login.requestHeaders["fido2AuthenticationOptionsPath"])
#set ($authenticationPath = $login.requestHeaders["fido2AuthenticationPath"])
#set ($statusServicePath = $login.requestHeaders["fido2StatusServicePath"])
#set ($userVerification = $login.requestHeaders["fido2UserVerification"])
<script>
let params = {
authenticationOptionsEndpoint: "$authenticationOptionsPath",
authenticationEndpoint: "$authenticationPath",
statusServiceEndpoint: "$statusServicePath",
userVerification: "$userVerification",
};
</script>
<script src="${login.appDataPath}/resources/simplewebauthn-browser@7.1.0.min.js"></script>
<script src="${login.appDataPath}/resources/fido2_utils.js"></script>
<script src="${login.appDataPath}/resources/fido2_auth_std.js"></script>
#end
#if ($gui.name == "fido2_onboard")
<script src="${login.appDataPath}/resources/base64.js"></script>
<script src="${login.appDataPath}/resources/fido2_utils.js"></script>
<script src="${login.appDataPath}/resources/fido2_onboard.js"></script>
#end
#if ($useFormEncryption)
<script src="${login.appDataPath}/resources/forge.bundle.js"></script>
<script src="${login.appDataPath}/resources/e2eenc.js"></script>
#end

View File

@ -0,0 +1,88 @@
## This template is used to respond with a JSON format
## In this case, the client is supposed to parse and show the data
## The JSON data is close to the XML format of the GuiDesc
#set ($target = $utils.escapeHtmlAttribute($gui.target.replaceAll('&?language=[^&]*','')))
{
"name" : "$gui.name" ,
"target" : "$target" #if ($gui.label || $gui.language || $gui.domain || $gui.getGuiElems().size() > 0 || $gui.getGuiGroup().size() > 0), #end ## if
#if ($gui.label) "label" : "$gui.label" #if ($gui.language || $gui.domain || $gui.getGuiElems().size() > 0 || $gui.getGuiGroup().size() > 0), #end ## if
#end ## if
#if ($gui.language) "language" : "$gui.language" #if ($gui.domain || $gui.getGuiElems().size() > 0 || $gui.getGuiGroup().size() > 0), #end ## if
#end ## if ($gui.language)
#if ($gui.domain) "domain" : "$gui.domain" #if ($gui.getGuiElems().size() > 0 || $gui.getGuiGroup().size() > 0), #end ## if
#end ## if ($gui.domain)
#if ($gui.getGuiElems().size() > 0)
"elements" : [
#set ($i = 0)
#foreach ($guiElem in $gui.getGuiElems())
{
"name" : "$guiElem.name",
"type" : "$guiElem.type",
"optional" : "$guiElem.optional",
"label" : "$guiElem.label" #if ($guiElem['validation-failed'] || $guiElem.value || $guiElem.length || $guiElem.format), #end
#if ($guiElem['validation-failed']) "validation-failed" : "$guiGroup.validationFailed" #if ($guiElem.value || $guiElem.length || $guiElem.format), #end
#end ## if ($guiElem['validation-failed'])
#if ($guiElem.value) "value" : "$guiElem.value.replaceAll('\\\\','_ESCAPED_BACKSLASH_').replaceAll('\\"','_ESCAPED_QUOTE_').replaceAll('\\','\\\\').replaceAll('"','\\"').replaceAll('_ESCAPED_BACKSLASH_','\\\\').replaceAll('_ESCAPED_QUOTE_','\\"')" #if ($guiElem.length || $guiElem.format), #end
#end ## if ($guiElem.value)
#if ($guiElem.length) "max-length" : "$guiElem.length" #if ($guiElem.format), #end
#end ## if ($guiElem.length)
#if ($guiElem.format) "format" : "$guiElem.format"
#end
}
#set ($i = $i + 1)
#if ($i < ($gui.getGuiElems().size())), #end
#end ## loop
] #if ($gui.getGuiGroup() && $gui.getGuiGroup().size() > 0), #end
#end ## if ($gui.getGuiGroup() && $gui.getGuiElem().size() > 0)
#if ($gui.getGuiGroup() && $gui.getGuiGroup().size() > 0)
"groups" : [
#set ($j = 0)
#foreach ($guiGroup in $gui.getGuiGroup())
"name" : "$guiGroup.name",
"type" : "$guiGroup.type",
"label" : "$guiGroup.label",
"multiple" : "$guiGroup.multiple",
"format" : "$guiGroup.format",
"optional" : "$guiGroup.optional",
"validation-failed" : "$guiGroup.validationFailed" #if ($gui.getGuiElems().length() > 0), #end
#if ($gui.getGuiElems() && $gui.getGuiElems().length() > 0)
"elements" : [
#set ($i = 0)
#foreach ($guiElem in $gui.getGuiElems())
{
"name" : "$guiElem.name",
"type" : "$guiElem.type",
"optional" : "$guiElem.optional",
"validation-failed" : "$guiGroup.validationFailed",
"label" : "$guiElem.label" #if ($guiElem.value || $guiElem.length || $guiElem.format), #end
#if ($guiElem.value)
"value" : "$guiElem.value.replaceAll('\\\\','_ESCAPED_BACKSLASH_').replaceAll('\\"','_ESCAPED_QUOTE_').replaceAll('\\','\\\\').replaceAll('"','\\"').replaceAll('_ESCAPED_BACKSLASH_','\\\\').replaceAll('_ESCAPED_QUOTE_','\\"')" #if ($guiElem.length || $guiElem.format), #end
#end ## if ($guiElem.value)
#if ($guiElem.length)
"max-length" : "$guiElem.length" #if ($guiElem.format), #end
#end ## if ($guiElem.length)
#if ($guiElem.format)
"format" : "$guiElem.format"
#end ## if ($guiElem.format)
}
#set ($i = $i + 1)
#if ($i < ($gui.getGuiElems().size())), #end
#end ## loop
] #if ($foreach.hasNext), #end
#set ($j = $j + 1)
#if ($j < ($gui.getGuiGroup().size())), #end
#end ## foreach ($guiGroup in $gui.getGuiGroup())
#end ## if ($gui.getGuiElem() && $gui.getGuiElem().size() > 0)
]
#end ## if ($gui.getGuiGroup() && $gui.getGuiGroup().length() > 0)
}

View File

@ -0,0 +1,32 @@
## Nav =================================================================
<nav id="language-switch" class="container-fluid">
<div class="dropdown pull-right">
<a id="language-switch-btn" class="dropdown-toggle text-uppercase small" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<strong id="language">$login.localeCode</strong>
<span class="caret"></span>
</a>
<ul class="dropdown-menu" aria-labelledby="language-switch-btn">
## loop over all defined languages/locales....
#foreach ($locale in $login.locales)
## find translated label of current locale
#if ($text.contains("language.$locale"))
#set ($langLabel = $text.get("language.$locale"))
#elseif ($locale.length() > 2)
#set ($langLabel = $text.get("language.${locale.substring(0,2).toLowercase()}"))
#else
#set ($langLabel = $locale)
#end
## emit link or text for each language
#if ($login.localeCode != $locale && $login.language != $locale)
#set ($langTarget = $utils.escapeHtmlAttribute($gui.target('language', $locale)))
<li>
<a class="lang" href="$langTarget">
<strong class="prefix text-primary text-uppercase">$locale</strong>
<span>$langLabel</span>
</a>
</li>
#end
#end ## end foreach
</ul>
</div>
</nav>

View File

@ -0,0 +1,295 @@
#macro(renderFormField $guiElem, $gui, $tabindex)
#if ($guiElem.type == "submit" || $guiElem.type == "button" || $guiElem.type == "reset" || $guiElem.type == "link")
## do nothing, will be rendered in renderFormControls nd renderFormLinks
#elseif ($guiElem.type == "info" || $guiElem.type == "error")
#if ($guiElem.label && $guiElem.label.length() > 0)
## special fields: display some text only
#set ($class = "form-group")
#if ($guiElem.type == "error")
#set ($class = "$class has-error")
#end
<div class="$class">
<div class="col-sm-offset-3 col-sm-6">
<span class="help-block small" id="$guiElem.name">
$guiElem.label
</span>
</div>
</div>
#end
#elseif ($guiElem.type == "hidden" && $guiElem.name == "saml.logoutURLs")
<script>
var sp_urls = '$guiElem.value'.split(',');
var final_url = '$gui.getGuiElem("saml.logoutURL").value';
function kill_session() {
var current_url = window.location.href;
if (current_url.indexOf('?logout') == -1 && current_url.indexOf('&logout') == -1) {
console.log("current URL does not terminate the IDP session");
var logout_url = '';
if (current_url.indexOf('?') > 0) {
logout_url = current_url + "&logout";
}
else {
logout_url = current_url + "?logout";
}
$.ajax({
type: "GET",
url: logout_url,
async: false,
xhrFields: {
withCredentials: true
},
dataType: "text",
success: function() {},
error: function() {}
});
}
}
var request_urls = sp_urls.filter(function(current_url) {
return current_url.indexOf('SAMLRequest') > 0;
});
var response_urls = sp_urls.filter(function(current_url) {
return current_url.indexOf('SAMLResponse') > 0;
});
function end_logout() {
if (response_urls.length == 0) {
console.log('IDP-initiated SAML logout detected');
kill_session(); // required to terminate IDP session
window.location.href = final_url;
}
else {
console.log('SP-initiated SAML logout detected');
kill_session(); // required to terminate IDP session
window.location.href = response_urls[0]; // only 1 such URL allowed. process ends on SP
}
}
var requests = [];
for (var i = 0; i < request_urls.length; i++) {
var current_url = request_urls[i];
requests.push($.ajax({
type: "GET",
url: current_url,
xhrFields: {
withCredentials: true
},
crossDomain: true,
dataType: 'jsonp',
error: function() {}
})
);
}
// send out the requests in parallel and afterwards terminate the logout process
// we have to terminate the logout no mather if the requests were successful or if there were failed requests
$.when.apply($, requests).then(function() { end_logout(); }, function() { end_logout(); });
</script>
#elseif ($guiElem.type == "hidden")
<input type="hidden" name="$guiElem.name" value="$utils.escapeHtml($guiElem.value)">
#else ## not info, error, button, submit, reset or hidden -> normal visual element
## define CSS class of representation in form
#set ($class = "form-group")
#if ($guiElem.optional)
#set ($class = "$class optional")
#else
#set ($class = "$class required")
#end
## highlight failed input validation, if flagged
#if ($guiElem.validationFailed && $guiElem.value && $guiElem.value.length() > 0)
#set ($class = "$class has-error")
#end
#if ($guiElem.validationFailed && (!$guiElem.value || $guiElem.value.length() == 0))
#set ($class = "$class has-error")
#end
## the form field's container, a label, and optionally a validation-related message
<div class="$class">
## Special handling required for radios + checkboxes
#if ($guiElem.type != "radio" && $guiElem.type != "checkbox")
<label class="col-sm-3 control-label" for="$guiElem.name">
#if ($guiElem.name.startsWith("inputField") && !$guiElem.optional)
$guiElem.label<span style="color: red">*</span>
#else
$guiElem.label
#end
</label>
<div class="col-sm-6">
#if ($guiElem.type == "text")
<input class="form-control" type="text" name="$guiElem.name" id="$guiElem.name"
maxlength="$guiElem.length"
value="$utils.escapeHtml($guiElem.value)" tabindex="$tabindex">
#elseif ($guiElem.type == "pw-text")
<div class="icon-inside">
<input name="${guiElem.name}" type="password" class="form-control" id="${guiElem.name}" value="$utils.escapeHtml($guiElem.value)" tabindex="$tabindex">
<button class="icon-button" type="button" onclick="toggleInputType('${guiElem.name}', '${guiElem.name}eye-icon', '${login.appDataPath}')">
<img id="${guiElem.name}eye-icon" src="${login.appDataPath}/resources/eye.svg">
</button>
</div>
#elseif ($guiElem.type == "select")
#set ($scrollSize = $guiElem.getGuiElems().size())
#set ($scrollSize = $math.min($scrollSize,4))
#if ($guiElem.multiple)
<select name="$guiElem.name" class="form-control" size="$scrollSize" multiple>
#else
<select name="$guiElem.name" class="form-control">
#end
#foreach ($option in $guiElem.getGuiElems())
#if ($option.selected)
<option value="$utils.escapeHtml($option.value)" selected>$option.label</option>
#else
<option value="$utils.escapeHtml($option.value)">$option.label</option>
#end
#end ## foreach option
</select>
#elseif ($guiElem.type == "image" )
<img src="$utils.escapeHtml($guiElem.value)" alt="$guiElem.label" />
#end
#if ($guiElem.validationMessage && $guiElem.validationMessage.length() > 0)
<span class="help-block small">$guiElem.validationMessage</span>
#end
#if ($jsValidation)
#renderElementValidation($guiElem, $gui)
#end
</div>
#else
## Special handling for checkboxes and radios
<div class="col-sm-offset-3 col-sm-6">
<label>
<input type="$guiElem.type" name="$guiElem.name"
value="$utils.escapeHtml($guiElem.value)"
#if ($guiElem.checked || $guiElem.value == 'true')
checked
#end
tabindex="$tabindex">
$guiElem.label
</label>
#if ($guiElem.validationMessage && $guiElem.validationMessage.length() > 0)
<span class="help-block small">$guiElem.validationMessage</span>
#end
#if ($jsValidation)
#renderElementValidation($guiElem, $gui)
#end
</div>
#end
</div>
#end
#end ## end macro
#macro(renderElementValidation $guiElem, $gui)
#if (($guiElem.validation && $guiElem.validation.length() > 0)||($guiElem.format && $guiElem.format.length() > 0))
<script type="text/javascript">
#if ($guiElem.validation && $guiElem.validation.length() > 0)
#if ($guiElem.validation.indexof('return ') > 0)
#set ($validationFunc="function () { $guiElem.validation }")
#else
#set ($validationFunc="function () { return $guiElem.validation ; }")
#end
#else
#set ($validationFunc="function () { return true; }")
#end
var form = document.getElementById('${gui.name}');
var formInput = form.elements["${guiElem.name}"];
formInput.onchange = function () {
var valid = ${validationFunc}.call(this);
#if ($guiElem.format && $guiElem.format.length() > 0)
valid = valid && (/${guiElem.format}/).test(this.value);
#end
var parent = this.parentNode;
if (!valid) {
parent.className += " has-error";
} else {
parent.className = parent.className.replace(/ has-error/g, '');
}
#if (!$guiElem.optional)
if (!this.value) {
parent.className += " has-warning";
} else {
parent.className = parent.className.replace(/ has-warning/g,'');
}
#end
};
</script>
#end
#end ## macro
#macro(renderFormLinks $gui)
#set ($noLinks = true)
#foreach ($guiElem in $gui.getGuiElems())
#if ($guiElem.type == "link")
#if ($noLinks)
<div class="form-group text-center">
#set ($noLinks = false)
#end
<a class="link" title="${utils.escapeHtml($guiElem.label)}" href="$utils.escapeHtml($guiElem.value)">${utils.escapeHtml($guiElem.label)}</a>
#end
#end
#if (!$noLinks)
</div>
#end
#end
#macro(renderFormControls $gui)
<div class="form-group text-center">
#set ($buttonClass = "btn")
#if ($isFormRequest)
#set ($buttonClass = "$buttonClass btn-default")
#else
#set ($buttonClass = "$buttonClass btn-primary")
#end
#foreach ($guiElem in $gui.getGuiElems())
#if ($guiElem.type == "submit" || $guiElem.type == "button" || $guiElem.type == "reset")
<button class="$buttonClass $guiElem.cssClass"
## special handling for button which execute a JS
#if ($guiElem.name == 'onclick')
type="button"
onClick="start()"
#else
name="$guiElem.name"
value="$utils.escapeHtml($guiElem.value)"
#end
>
#if ($guiElem.icon != "")
#if ($guiElem.icon.contains("http"))
<img src="$guiElem.icon" class="$guiElem.iconCssClass" />
#else
<img src="${login.appDataPath}/resources/$guiElem.icon" class="$guiElem.iconCssClass" />
#end
#end
$utils.escapeHtml($guiElem.label)
</button>
#end
#end ## foreach
</div>
#end ## end macro

View File

@ -46,18 +46,21 @@ spec:
podDisruptionBudget:
maxUnavailable: "50%"
git:
tag: "r-603573b16dce3bad3093656c6cd14820e69672b4"
tag: "r-273c80f3ed81849ff45349dd7d23b000a9535c6f"
dir: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT/DEFAULT-ADN-POST-IAM-TKNXCHNG-INV/npi"
credentials: "git-credentials"
keystores:
- "npi-3b41ca4ca1c4028117d16f5b"
- "npi-23dc4a9fcc79a12d82662747"
- "npi-new-automatic-key-store"
- "npi-new-authentication-realm-identity"
- "npi-keystore-proxy-auth"
- "npi-cossa-realm-identity"
truststores:
- "npi-new-automatic-trust-store"
- "npi-trsutstore-proxy-auth"
- "npi-cossa-realm-signer-trust"
- "npi-new-authentication-realm-tls-trust"
- "npi-cossa-realm-tls-trust"
- "npi-new-authentication-realm-signer-trust"
ingresses:
- "npi"
podSecurity:

View File

@ -1,7 +1,7 @@
apiVersion: "operator.nevis-security.ch/v1"
kind: "NevisKeyStore"
metadata:
name: "npi-new-automatic-key-store"
name: "npi-keystore-proxy-auth"
namespace: "adn-postit-tknxchng-01-dev"
labels:
deploymentTarget: "npi"

View File

@ -0,0 +1,18 @@
apiVersion: "operator.nevis-security.ch/v1"
kind: "NevisKeyStore"
metadata:
name: "npi-new-authentication-realm-identity"
namespace: "adn-postit-tknxchng-01-dev"
labels:
deploymentTarget: "npi"
annotations:
projectKey: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT"
patternId: "92e282d1dc2b69d9e4f91fc0"
spec:
cn: "npi"
usage: "<reserved for future use>"
san:
dns:
- "npi"
- "npi.adn-postit-tknxchng-01-dev"
email: []

View File

@ -0,0 +1,14 @@
apiVersion: "operator.nevis-security.ch/v1"
kind: "NevisTrustStore"
metadata:
name: "npi-new-authentication-realm-signer-trust"
namespace: "adn-postit-tknxchng-01-dev"
labels:
deploymentTarget: "npi"
annotations:
projectKey: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT"
patternId: "92e282d1dc2b69d9e4f91fc0"
spec:
keystores:
- name: "nai-sh4r3d-default-default-signer"
namespace: "adn-postit-tknxchng-01-dev"

View File

@ -0,0 +1,14 @@
apiVersion: "operator.nevis-security.ch/v1"
kind: "NevisTrustStore"
metadata:
name: "npi-new-authentication-realm-tls-trust"
namespace: "adn-postit-tknxchng-01-dev"
labels:
deploymentTarget: "npi"
annotations:
projectKey: "DEFAULT-ADN-POST-IAM-TKNXCHNG-PROJECT"
patternId: "92e282d1dc2b69d9e4f91fc0"
spec:
keystores:
- name: "nai-default-identity"
namespace: "adn-postit-tknxchng-01-dev"

View File

@ -1,7 +1,7 @@
apiVersion: "operator.nevis-security.ch/v1"
kind: "NevisTrustStore"
metadata:
name: "npi-new-automatic-trust-store"
name: "npi-trsutstore-proxy-auth"
namespace: "adn-postit-tknxchng-01-dev"
labels:
deploymentTarget: "npi"

View File

@ -38,7 +38,7 @@
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<init-param>
<param-name>LoginRendererServlet</param-name>
<param-value>LoginRenderer_New_nevisLogrend_Instance</param-value>
<param-value>LoginRenderer_nli</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<init-param>
@ -91,12 +91,12 @@
</filter>
<!-- source: pattern://cc0434226c610ad74ffbf1d1 -->
<filter>
<filter-name>ModSecurity_cossa_realm_REST2</filter-name>
<filter-name>ModSecurity_cossa_realm_TokenIntrospection</filter-name>
<filter-class>ch::nevis::nevisproxy::filter::modsecurity::ModsecurityFilter</filter-class>
<!-- source: pattern://cc0434226c610ad74ffbf1d1 -->
<init-param>
<param-name>ConfigFile</param-name>
<param-value>/var/opt/nevisproxy/default/host-cossa.agov-w.azure.adnovum.net/WEB-INF/security_cossa_realm_rest2.conf</param-value>
<param-value>/var/opt/nevisproxy/default/host-cossa.agov-w.azure.adnovum.net/WEB-INF/security_cossa_realm_tokenintrospection.conf</param-value>
</init-param>
</filter>
<!-- source: pattern://23dc4a9fcc79a12d82662747 -->
@ -190,7 +190,7 @@
</filter-mapping>
<!-- source: pattern://cc0434226c610ad74ffbf1d1 -->
<filter-mapping>
<filter-name>ModSecurity_cossa_realm_REST2</filter-name>
<filter-name>ModSecurity_cossa_realm_TokenIntrospection</filter-name>
<url-pattern>/oauth/introspect2/*</url-pattern>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
@ -255,7 +255,7 @@
</servlet>
<!-- source: pattern://cc0434226c610ad74ffbf1d1, pattern://cc0434226c610ad74ffbf1d1#allowedMethods, pattern://cc0434226c610ad74ffbf1d1#backends, pattern://cc0434226c610ad74ffbf1d1#keystore, pattern://cc0434226c610ad74ffbf1d1#responseRewrite, pattern://cc0434226c610ad74ffbf1d1#truststore -->
<servlet>
<servlet-name>Connector_cossa_realm_REST2</servlet-name>
<servlet-name>Connector_cossa_realm_TokenIntrospection</servlet-name>
<!-- source: pattern://cc0434226c610ad74ffbf1d1 -->
<servlet-class>ch::nevis::isiweb4::servlet::connector::http::HttpsConnectorServlet</servlet-class>
<!-- source: pattern://cc0434226c610ad74ffbf1d1#allowedMethods -->
@ -306,17 +306,17 @@
<!-- source: pattern://cc0434226c610ad74ffbf1d1#truststore -->
<init-param>
<param-name>SSLCACertificateFile</param-name>
<param-value>/var/opt/keys/trust/npi-new-automatic-trust-store/truststore.pem</param-value>
<param-value>/var/opt/keys/trust/npi-trsutstore-proxy-auth/truststore.pem</param-value>
</init-param>
<!-- source: pattern://cc0434226c610ad74ffbf1d1#keystore -->
<init-param>
<param-name>SSLClientCertificateFile</param-name>
<param-value>/var/opt/keys/own/npi-new-automatic-key-store/cert.pem</param-value>
<param-value>/var/opt/keys/own/npi-keystore-proxy-auth/cert.pem</param-value>
</init-param>
<!-- source: pattern://cc0434226c610ad74ffbf1d1#keystore -->
<init-param>
<param-name>SSLClientKeyFile</param-name>
<param-value>/var/opt/keys/own/npi-new-automatic-key-store/key.pem</param-value>
<param-value>/var/opt/keys/own/npi-keystore-proxy-auth/key.pem</param-value>
</init-param>
<!-- source: pattern://cc0434226c610ad74ffbf1d1 -->
<init-param>
@ -363,7 +363,7 @@
</servlet>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet>
<servlet-name>LoginRenderer_New_nevisLogrend_Instance</servlet-name>
<servlet-name>LoginRenderer_nli</servlet-name>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-class>ch::nevis::isiweb4::servlet::rendering::LoginRendererServlet</servlet-class>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
@ -374,12 +374,12 @@
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<init-param>
<param-name>RenderingProvider</param-name>
<param-value>remote:NevisLogrendConnector_New_nevisLogrend_Instance:/nevislogrend/index.vm?logrendresourcepath=/nevislogrend</param-value>
<param-value>remote:NevisLogrendConnector_nli:/nevislogrend/index.vm?logrendresourcepath=/nevislogrend</param-value>
</init-param>
</servlet>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet>
<servlet-name>NevisLogrendConnector_New_nevisLogrend_Instance</servlet-name>
<servlet-name>NevisLogrendConnector_nli</servlet-name>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-class>ch::nevis::isiweb4::servlet::connector::http::HttpConnectorServlet</servlet-class>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
@ -405,12 +405,12 @@
</servlet>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-mapping>
<servlet-name>NevisLogrendConnector_New_nevisLogrend_Instance</servlet-name>
<servlet-name>NevisLogrendConnector_nli</servlet-name>
<url-pattern>/nevislogrend/*</url-pattern>
</servlet-mapping>
<!-- source: pattern://cc0434226c610ad74ffbf1d1, pattern://cc0434226c610ad74ffbf1d1#path -->
<servlet-mapping>
<servlet-name>Connector_cossa_realm_REST2</servlet-name>
<servlet-name>Connector_cossa_realm_TokenIntrospection</servlet-name>
<url-pattern>/oauth/introspect2/*</url-pattern>
</servlet-mapping>
<!-- source: pattern://4b8f4de5fefd5f33774df841 -->

View File

@ -1,66 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "/opt/nevisproxy/dtd/web-app_2_3.dtd">
<web-app>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<context-param>
<param-name>SectokenVerifierCert</param-name>
<param-value>/var/opt/keys/trust/npi-cossa-realm-signer-trust/truststore.pem</param-value>
<param-value>/var/opt/keys/trust/npi-new-authentication-realm-signer-trust/truststore.pem</param-value>
</context-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171, pattern://92e282d1dc2b69d9e4f91fc0 -->
<filter>
<filter-name>AuthenticationService_cossa_realm</filter-name>
<filter-name>Authentication_New_Authentication_Realm</filter-name>
<filter-class>ch::nevis::isiweb4::filter::auth::IdentityCreationFilter</filter-class>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>AuthenticationServlet</param-name>
<param-value>Connector_cossa_realm</param-value>
<param-value>Connector_New_Authentication_Realm</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<init-param>
<param-name>BodyReadSize</param-name>
<param-value>32768</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>EntryPointID</param-name>
<param-value>klp.agov-w.azure.adnovum.net</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>InactiveInterval</param-name>
<param-value>7200</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<init-param>
<param-name>InterceptionRedirect</param-name>
<param-value>never</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>LoginRendererServlet</param-name>
<param-value>LoginRenderer_New_nevisLogrend_Instance</param-value>
<param-value>LoginRenderer_nli</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Realm</param-name>
<param-value>cossa_realm</param-value>
<param-value>New_Authentication_Realm</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<init-param>
<param-name>RecheckAuthentication</param-name>
<param-value>On</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>RenewIdentification</param-name>
<param-value>true</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>StateKey</param-name>
<param-value>cossa_realm</param-value>
<param-value>New_Authentication_Realm</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>StoreInterceptedRequest</param-name>
<param-value>false</param-value>
@ -89,33 +74,6 @@
</param-value>
</init-param>
</filter>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<filter>
<filter-name>OAuth_Preflighted_CORS_New OAuth 2.0 Authorization Server / OpenID Provider</filter-name>
<filter-class>ch::nevis::isiweb4::filter::lua::LuaFilter</filter-class>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<init-param>
<param-name>Script</param-name>
<param-value>
function inputHeader(request, response)
response:setHeader("Access-Control-Allow-Origin", "*")
response:setHeader("Access-Control-Allow-Credentials", "true")
response:setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS")
response:setHeader("Access-Control-Allow-Headers", "Authorization")
response:setHeader("Access-Control-Expose-Headers", "*")
response:setHeader("Access-Control-Max-Age", "600")
if request:getMethod() == "OPTIONS" then
response:send(204)
end
end
</param-value>
</init-param>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<init-param>
<param-name>Script.InputHeaderFunctionName</param-name>
<param-value>inputHeader</param-value>
</init-param>
</filter>
<!-- source: pattern://3b41ca4ca1c4028117d16f5b -->
<filter>
<filter-name>ResponseHeader_Default</filter-name>
@ -130,46 +88,46 @@
</param-value>
</init-param>
</filter>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171, pattern://92e282d1dc2b69d9e4f91fc0 -->
<filter>
<filter-name>SessionHandler_cossa_realm</filter-name>
<filter-name>SessionHandler_New_Authentication_Realm</filter-name>
<filter-class>ch::nevis::nevisproxy::filter::session::SessionManagementFilter</filter-class>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Cookie.ExtraAttributes</param-name>
<param-value>SameSite=None</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Cookie.Name</param-name>
<param-value>Session_cossa_realm</param-value>
<param-value>Session_New_Authentication_Realm</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Cookie.Secure</param-name>
<param-value>true</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Identification</param-name>
<param-value>COOKIE</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>MaxInactiveInterval</param-name>
<param-value>600</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>MaxLifetime</param-name>
<param-value>28800</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Servlet</param-name>
<param-value>LocalSessionStoreServlet</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>UpdateTimeStampMinInterval</param-name>
<param-value>120</param-value>
@ -185,174 +143,105 @@
<filter-name>ResponseHeader_Default</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<!-- source: pattern://8523f0587aa8cfa7008f8171, pattern://92e282d1dc2b69d9e4f91fc0 -->
<filter-mapping>
<filter-name>OAuth_Preflighted_CORS_New OAuth 2.0 Authorization Server / OpenID Provider</filter-name>
<url-pattern>/oauth/authorize</url-pattern>
<filter-name>SessionHandler_New_Authentication_Realm</filter-name>
<url-pattern>/*</url-pattern>
<exclude-url-regex>^/errorpages.*$|^/favicon.ico$|^/hallo.txt$|^/index.html$|^/nevislogrend/.*$|^/resources.*$</exclude-url-regex>
</filter-mapping>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<!-- source: pattern://8523f0587aa8cfa7008f8171, pattern://92e282d1dc2b69d9e4f91fc0 -->
<filter-mapping>
<filter-name>OAuth_Preflighted_CORS_New OAuth 2.0 Authorization Server / OpenID Provider</filter-name>
<url-pattern>/oauth/token</url-pattern>
<filter-name>Authentication_New_Authentication_Realm</filter-name>
<url-pattern>/*</url-pattern>
<exclude-url-regex>^/errorpages.*$|^/favicon.ico$|^/hallo.txt$|^/index.html$|^/nevislogrend/.*$|^/resources.*$</exclude-url-regex>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<filter-mapping>
<filter-name>SessionHandler_cossa_realm</filter-name>
<url-pattern>/oauth/authorize</url-pattern>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<filter-mapping>
<filter-name>SessionHandler_cossa_realm</filter-name>
<url-pattern>/oauth/token</url-pattern>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<filter-mapping>
<filter-name>AuthenticationService_cossa_realm</filter-name>
<url-pattern>/oauth/authorize</url-pattern>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<filter-mapping>
<filter-name>AuthenticationService_cossa_realm</filter-name>
<url-pattern>/oauth/token</url-pattern>
</filter-mapping>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<listener>
<listener-class>ch::nevis::isiweb4::listener::SessionListener</listener-class>
</listener>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<servlet>
<servlet-name>Connector_cossa_realm</servlet-name>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<servlet-name>Connector_New_Authentication_Realm</servlet-name>
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<servlet-class>ch::nevis::isiweb4::servlet::connector::soap::esauth4::Esauth4ConnectorServlet</servlet-class>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.DNSCache.ttl</param-name>
<param-value>60</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.InetAddress</param-name>
<param-value>nai:8991</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.KeepAlive.LifeTime</param-name>
<param-value>30</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.RequestTimeout</param-name>
<param-value>90000</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.ResourceManager.RetryTimeout</param-name>
<param-value>0</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.SSLCACertificateFile</param-name>
<param-value>/var/opt/keys/trust/npi-cossa-realm-tls-trust/truststore.pem</param-value>
<param-value>/var/opt/keys/trust/npi-new-authentication-realm-tls-trust/truststore.pem</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.SSLCheckPeerHostname</param-name>
<param-value>false</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.SSLClientCertificateFile</param-name>
<param-value>/var/opt/keys/own/npi-cossa-realm-identity/cert.pem</param-value>
<param-value>/var/opt/keys/own/npi-new-authentication-realm-identity/cert.pem</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>Transport.SSLClientKeyFile</param-name>
<param-value>/var/opt/keys/own/npi-cossa-realm-identity/key.pem</param-value>
<param-value>/var/opt/keys/own/npi-new-authentication-realm-identity/key.pem</param-value>
</init-param>
</servlet>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<servlet>
<servlet-name>Connector_cossa_realm_REST</servlet-name>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<servlet-class>ch::nevis::isiweb4::servlet::connector::http::HttpsConnectorServlet</servlet-class>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<servlet-name>Hosting_New_Hosting_Service</servlet-name>
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<servlet-class>ch::nevis::nevisproxy::servlet::file::FileReaderServlet</servlet-class>
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<init-param>
<param-name>DNSCache.ttl</param-name>
<param-value>60</param-value>
<param-name>Profile</param-name>
<param-value>AllowSubDirectories</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<init-param>
<param-name>InetAddress</param-name>
<param-value>nai:8991</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>KeepAlive.LifeTime</param-name>
<param-value>30</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>MappingType</param-name>
<param-value>requesturi</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>RequestTimeout</param-name>
<param-value>90000</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>ResourceManager.RetryTimeout</param-name>
<param-value>0</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>SSLCACertificateFile</param-name>
<param-value>/var/opt/keys/trust/npi-cossa-realm-tls-trust/truststore.pem</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>SSLCheckPeerHostname</param-name>
<param-value>false</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>SSLClientCertificateFile</param-name>
<param-value>/var/opt/keys/own/npi-cossa-realm-identity/cert.pem</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>SSLClientKeyFile</param-name>
<param-value>/var/opt/keys/own/npi-cossa-realm-identity/key.pem</param-value>
</init-param>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<init-param>
<param-name>URIPrefix</param-name>
<param-value>/nevisauth</param-value>
<param-name>RootDirectory</param-name>
<param-value>/var/opt/nevisproxy/default/host-klp.agov-w.azure.adnovum.net/</param-value>
</init-param>
</servlet>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<servlet>
<servlet-name>Hosting_Default</servlet-name>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<servlet-class>ch::nevis::isiweb4::servlet::defaults::DefaultServlet</servlet-class>
</servlet>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<servlet>
<servlet-name>LocalSessionStoreServlet</servlet-name>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<servlet-class>ch::nevis::nevisproxy::servlet::cache::local::LocalSessionStoreServlet</servlet-class>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>MaxInactiveInterval</param-name>
<param-value>600</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>MaxLifetime</param-name>
<param-value>28800</param-value>
</init-param>
<!-- source: pattern://b67f81a971e4c08aa79040a2 -->
<!-- source: pattern://8523f0587aa8cfa7008f8171 -->
<init-param>
<param-name>MemorySize</param-name>
<param-value>512000000</param-value>
@ -360,7 +249,7 @@
</servlet>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet>
<servlet-name>LoginRenderer_New_nevisLogrend_Instance</servlet-name>
<servlet-name>LoginRenderer_nli</servlet-name>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-class>ch::nevis::isiweb4::servlet::rendering::LoginRendererServlet</servlet-class>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
@ -371,12 +260,12 @@
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<init-param>
<param-name>RenderingProvider</param-name>
<param-value>remote:NevisLogrendConnector_New_nevisLogrend_Instance:/nevislogrend/index.vm?logrendresourcepath=/nevislogrend</param-value>
<param-value>remote:NevisLogrendConnector_nli:/nevislogrend/index.vm?logrendresourcepath=/nevislogrend</param-value>
</init-param>
</servlet>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet>
<servlet-name>NevisLogrendConnector_New_nevisLogrend_Instance</servlet-name>
<servlet-name>NevisLogrendConnector_nli</servlet-name>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-class>ch::nevis::isiweb4::servlet::connector::http::HttpConnectorServlet</servlet-class>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
@ -400,29 +289,39 @@
<param-value>/nevislogrend</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>Hosting_Default</servlet-name>
<servlet-class>ch::nevis::isiweb4::servlet::defaults::DefaultServlet</servlet-class>
</servlet>
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<servlet-mapping>
<servlet-name>Hosting_New_Hosting_Service</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<!-- source: pattern://7dc20659babc66c4401ce0dd -->
<servlet-mapping>
<servlet-name>NevisLogrendConnector_New_nevisLogrend_Instance</servlet-name>
<servlet-name>NevisLogrendConnector_nli</servlet-name>
<url-pattern>/nevislogrend/*</url-pattern>
</servlet-mapping>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/oauth/authorize</url-pattern>
</servlet-mapping>
<!-- source: pattern://0daf10449dab098fcc4b9311 -->
<servlet-mapping>
<servlet-name>Connector_cossa_realm_REST</servlet-name>
<url-pattern>/oauth/introspect</url-pattern>
</servlet-mapping>
<!-- source: pattern://b9366aa4b5d4572afa59ea4c -->
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/oauth/token</url-pattern>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/*</url-pattern>
<url-pattern>/favicon.ico</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/hallo.txt</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Hosting_Default</servlet-name>
<url-pattern>/errorpages/*</url-pattern>
</servlet-mapping>
<!-- source: pattern://3b41ca4ca1c4028117d16f5b -->
<mime-mapping>
@ -444,4 +343,9 @@
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<!-- source: pattern://8a4997cddc02803b920c8ee9 -->
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
</web-app>