Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
8255674
custom parameters to server requests
lukasmatusiewicz Nov 11, 2025
60d02e6
tests
lukasmatusiewicz Nov 11, 2025
b3d62b0
Update privacyIDEAADFSProvider.csproj
lukasmatusiewicz Nov 11, 2025
1ef83d5
Update RegistryReader.cs
lukasmatusiewicz Nov 11, 2025
ff3cd78
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 11, 2025
9eae919
Update PIWebAuthnSignRequest.cs
lukasmatusiewicz Nov 11, 2025
53295b0
Update PIResponse.cs
lukasmatusiewicz Nov 11, 2025
74f8cec
Update PILog.cs
lukasmatusiewicz Nov 11, 2025
c5ba5df
Update PIEnrollResponse.cs
lukasmatusiewicz Nov 11, 2025
5caa67a
Update PIChallenge.cs
lukasmatusiewicz Nov 11, 2025
44e94d4
Update PIAuthenticationStatus.cs
lukasmatusiewicz Nov 11, 2025
327e403
Update Configuration.cs
lukasmatusiewicz Nov 11, 2025
13411b4
Update privacyIDEAADFSProvider.sln
lukasmatusiewicz Nov 11, 2025
e569001
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 11, 2025
b135c61
Merge branch 'main' into 52-feature-forward-client-ip-and-client-user…
lukasmatusiewicz Nov 11, 2025
d2cb295
custom parameters to server requests
lukasmatusiewicz Nov 11, 2025
d85642e
tests
lukasmatusiewicz Nov 11, 2025
768d69a
Update privacyIDEAADFSProvider.csproj
lukasmatusiewicz Nov 11, 2025
b430726
Update RegistryReader.cs
lukasmatusiewicz Nov 11, 2025
8632a41
Update PIWebAuthnSignRequest.cs
lukasmatusiewicz Nov 11, 2025
ecad165
Update PIResponse.cs
lukasmatusiewicz Nov 11, 2025
ad89809
Update PILog.cs
lukasmatusiewicz Nov 11, 2025
63786f9
Update PIEnrollResponse.cs
lukasmatusiewicz Nov 11, 2025
dbfcc5b
Update PIChallenge.cs
lukasmatusiewicz Nov 11, 2025
9d72252
Update PIAuthenticationStatus.cs
lukasmatusiewicz Nov 11, 2025
10d4842
Update Configuration.cs
lukasmatusiewicz Nov 11, 2025
d9ab67d
Update privacyIDEAADFSProvider.sln
lukasmatusiewicz Nov 11, 2025
fa0114d
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 11, 2025
4ea903a
Update privacyIDEAADFSProvider/Adapter.cs
lukasmatusiewicz Nov 11, 2025
7979369
Create PIConstants.cs
lukasmatusiewicz Nov 11, 2025
e746616
Update PIEnrollResponse.cs
lukasmatusiewicz Nov 11, 2025
06c6abe
Update PIResponse.cs
lukasmatusiewicz Nov 11, 2025
a0ebb07
Update Adapter.cs
lukasmatusiewicz Nov 12, 2025
96bbf41
Update privacyIDEAADFSProvider.csproj
lukasmatusiewicz Nov 12, 2025
1f86095
Update PIConstants.cs
lukasmatusiewicz Nov 12, 2025
0a116db
Update privacyIDEAADFSProvider.csproj
lukasmatusiewicz Nov 12, 2025
513a52c
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 12, 2025
d37efaf
Merge branch '52-feature-forward-client-ip-and-client-user-agent' int…
lukasmatusiewicz Nov 12, 2025
f243fd0
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 12, 2025
ef64056
Update Adapter.cs
lukasmatusiewicz Nov 12, 2025
0367bf1
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 12, 2025
f15d9c3
Update PIConstants.cs
lukasmatusiewicz Nov 12, 2025
7cecc20
Update Adapter.cs
lukasmatusiewicz Nov 12, 2025
29ab884
Update PIConstants.cs
lukasmatusiewicz Nov 12, 2025
68f8acc
Update PIConstants.cs
lukasmatusiewicz Nov 12, 2025
3c3da69
Update PIResponse.cs
lukasmatusiewicz Nov 12, 2025
587d1ac
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 12, 2025
83ea1a1
Update AuthPage.html
lukasmatusiewicz Nov 12, 2025
a6a0fdb
Update FormResult.cs
lukasmatusiewicz Nov 12, 2025
df43096
Update AdapterPresentationForm.cs
lukasmatusiewicz Nov 12, 2025
50d412e
Update PIResponse.cs
lukasmatusiewicz Nov 12, 2025
73d9643
Update Adapter.cs
lukasmatusiewicz Nov 13, 2025
a835edb
final fix
lukasmatusiewicz Nov 13, 2025
de7d670
Update privacyIDEAADFSProvider/Adapter.cs
lukasmatusiewicz Nov 13, 2025
5fc9f98
rename user agent const
lukasmatusiewicz Nov 13, 2025
4d12786
Merge branch '54-enroll-via-multichallenge-optional' of https://githu…
lukasmatusiewicz Nov 13, 2025
0700ad9
Merge branch 'main' into 54-enroll-via-multichallenge-optional
lukasmatusiewicz Nov 13, 2025
024b9e6
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 13, 2025
2ca926c
Merge branch '54-enroll-via-multichallenge-optional' of https://githu…
lukasmatusiewicz Nov 13, 2025
84a7c27
Update PrivacyIDEA.cs
lukasmatusiewicz Nov 13, 2025
32c26ea
extract method for tr id collector
lukasmatusiewicz Nov 13, 2025
2905b82
move code from long if-else block to more readable methods
lukasmatusiewicz Nov 13, 2025
4fc9c4d
change var to let or const
lukasmatusiewicz Nov 13, 2025
5f40d1e
Update privacyIDEAADFSProvider/Adapter.cs
lukasmatusiewicz Nov 13, 2025
4052552
Update PIConstants.cs
lukasmatusiewicz Nov 13, 2025
cfbe145
Merge branch '54-enroll-via-multichallenge-optional' of https://githu…
lukasmatusiewicz Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
327 changes: 221 additions & 106 deletions privacyIDEAADFSProvider/Adapter.cs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions privacyIDEAADFSProvider/AdapterPresentationForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class AdapterPresentationForm : IAdapterPresentationForm
public string PasskeyChallenge { get; set; } = "";
public string PasskeyRegistration { get; set; } = "";
public string DisablePasskey { get; set; } = "";
public string IsEnrollmentViaMultichallengeOptional { get; set; } = "0";
public string EnrollmentLink { get; set; } = "";
public string DisableOTP { get; set; } = "0"; // used for enroll_via_multichallenge with push, where the only option is push

Expand Down Expand Up @@ -113,6 +114,7 @@ public string GetFormHtml(int lcid)
htmlTemplate = htmlTemplate.Replace("#disablePasskey#", DisablePasskey);
htmlTemplate = htmlTemplate.Replace("#passkeyChallenge#", PasskeyChallenge.Replace("\"", """));
htmlTemplate = htmlTemplate.Replace("#passkeyRegistration#", PasskeyRegistration.Replace("\"", """));
htmlTemplate = htmlTemplate.Replace("#isEnrollmentViaMultichallengeOptional#", IsEnrollmentViaMultichallengeOptional);
return htmlTemplate;
}

Expand Down
71 changes: 46 additions & 25 deletions privacyIDEAADFSProvider/AuthPage.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@
<input id="context" type="hidden" name="Context" value="%Context%" />
<!-- End inputs are required by the presentation framework. -->

<!-- Cancel Enrollment -->
<input id="cancelEnrollmentButton" name="cancelEnrollmentButton" type="button" value="Cancel Enrollment" onclick="cancelEnrollmentViaMc()"
aria-label="Cancel Enrollment"
style="background-color: rgb(220, 53, 69); border: none; border-style: solid; border-width: 1px; height: 35px;
min-width: 160px; width: auto; color: white; margin-bottom: 8px; user-select: none; padding: 8px 25px 12px 25px;" />

<p id="pageIntroductionText" style="color:red">#ERROR#</p>
<br />
<label for="otp" class="block" aria-label="#MESSAGE#">#MESSAGE#</label>
<input id="otp" name="otp" type="password" value="" class="text" placeholder="#OTPTEXT#" size="35" autocomplete="new-password" autofocus />
<input id="submitButton" type="submit" name="Submit" value="#SUBMIT#" onclick="submitForm()" />

<!-- Hidden inputs to persist state -->
<input id="autoSubmit" type="hidden" name="autoSubmit" value="#autoSubmit#" />
<input id="mode" type="hidden" name="mode" value="#mode#" />
<input id="pushAvailable" type="hidden" name="pushAvailable" value="#pushAvailable#" />
Expand All @@ -27,6 +34,8 @@
<input id="disablePasskey" type="hidden" name="disablePasskey" value="#disablePasskey#" />
<input id="autoSubmitLength" type="hidden" name="autoSubmitLength" value="#autoSubmitLength#" />
<input id="formResult" type="hidden" name="formResult" value="" />
<input id="isEnrollmentViaMultichallengeOptional" type="hidden" name="isEnrollmentViaMultichallengeOptional"
value="#isEnrollmentViaMultichallengeOptional#" />
<input id="disableOTP" type="hidden" name="disableOTP" value="#disableOTP#" />

<!-- Extra inputs to persist some data -->
Expand Down Expand Up @@ -79,9 +88,11 @@
passkeySignResponse: "",
passkeyRegistrationResponse: "",
origin: "",
enrollmentCancelled: false
};
disable("retryPasskeyLogin");
disable("retryPasskeyRegistration");
disable("cancelEnrollmentButton");

if (value("autoSubmit") === "1") {
submitForm();
Expand Down Expand Up @@ -128,13 +139,17 @@
disable("useOTPButton");
}

if (value("isEnrollmentViaMultichallengeOptional") === "1") {
enable("cancelEnrollmentButton");
}

// Set UI according to mode
if (value("mode") === "push") {
const pollingIntervals = [3, 2, 2, 1];
disable("otp");
disable("usePushButton");
disable("submitButton");
var refreshTime = 2;
let refreshTime = 2;
if (value("authCounter") > (pollingIntervals.length - 1)) {
refreshTime = pollingIntervals[(pollingIntervals.length - 1)];
} else {
Expand Down Expand Up @@ -190,6 +205,12 @@
}

// Helper functions

function cancelEnrollmentViaMc() {
formResult.enrollmentCancelled = true;
submitForm();
}

function setLoginOptionsVisibility() {
let ids = ["passkeyLoginButton", "retryPasskeyLogin", "useOTPButton", "usePushButton", "useWebAuthnButton"]
let shouldShow = false;
Expand Down Expand Up @@ -230,7 +251,7 @@


function value(id) {
var element = document.querySelector("#" + id);
const element = document.querySelector("#" + id);
if (element != null) {
return element.value;
} else {
Expand All @@ -240,7 +261,7 @@
}

function set(id, value) {
var element = document.querySelector("#" + id);
const element = document.querySelector("#" + id);
if (element != null) {
element.value = value;
} else {
Expand All @@ -249,7 +270,7 @@
}

function disable(id) {
var element = document.querySelector("#" + id);
const element = document.querySelector("#" + id);
if (element != null) {
element.style.display = "none";
} else {
Expand All @@ -258,7 +279,7 @@
}

function enable(id) {
var element = document.querySelector("#" + id);
const element = document.querySelector("#" + id);
if (element != null) {
element.style.display = "initial";
} else {
Expand All @@ -279,7 +300,7 @@
}

function copyTOTP() {
var copyText = document.querySelector("#enrollmentValue");
const copyText = document.querySelector("#enrollmentValue");
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
navigator.clipboard.writeText(copyText.value);
Expand Down Expand Up @@ -466,9 +487,9 @@
}

function utf8ArrToStr(aBytes) {
var sView = "";
let sView = "";

for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
for (let nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
nPart = aBytes[nIdx];
sView += String.fromCharCode(
nPart > 251 && nPart < 254 && nIdx + 5 < nLen ?
Expand Down Expand Up @@ -505,13 +526,13 @@
}

function strToUtf8Arr(sDOMStr) {
var aBytes;
var nChr;
var nStrLen = sDOMStr.length;
var nArrLen = 0;
let aBytes;
let nChr;
let nStrLen = sDOMStr.length;
let nArrLen = 0;

// Determine the byte-length of the string when encoded as UTF-8.
for (var nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) {
for (let nMapIdx = 0; nMapIdx < nStrLen; nMapIdx++) {
nChr = sDOMStr.charCodeAt(nMapIdx);
nArrLen += nChr < 0x80 ?
1
Expand All @@ -530,7 +551,7 @@
aBytes = new Uint8Array(nArrLen);

// Perform the encoding.
for (var nIdx = 0, nChrIdx = 0; nIdx < nArrLen; nChrIdx++) {
for (let nIdx = 0, nChrIdx = 0; nIdx < nArrLen; nChrIdx++) {
nChr = sDOMStr.charCodeAt(nChrIdx);
if (nChr < 128) {
/* one byte */
Expand Down Expand Up @@ -572,15 +593,15 @@
}

function base64DecToArr(sBase64, nBlockSize) {
var sB64Enc = sBase64.replace(/[^A-Za-z0-9+\/]/g, "");
var nInLen = sB64Enc.length;
var nOutLen = nBlockSize ?
let sB64Enc = sBase64.replace(/[^A-Za-z0-9+\/]/g, "");
let nInLen = sB64Enc.length;
let nOutLen = nBlockSize ?
Math.ceil((nInLen * 3 + 1 >>> 2) / nBlockSize) * nBlockSize
:
nInLen * 3 + 1 >>> 2;
var aBytes = new Uint8Array(nOutLen);
let aBytes = new Uint8Array(nOutLen);

for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
for (let nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 18 - 6 * nMod4;
if (nMod4 === 3 || nInLen - nInIdx === 1) {
Expand All @@ -595,11 +616,11 @@
};

function base64EncArr(bytes) {
var aBytes = new Uint8Array(bytes)
var eqLen = (3 - (aBytes.length % 3)) % 3;
var sB64Enc = "";
let aBytes = new Uint8Array(bytes)
let eqLen = (3 - (aBytes.length % 3)) % 3;
let sB64Enc = "";

for (var nMod3, nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
for (let nMod3, nLen = aBytes.length, nUint24 = 0, nIdx = 0; nIdx < nLen; nIdx++) {
nMod3 = nIdx % 3;

// Split the output in lines 76-characters long
Expand All @@ -625,7 +646,7 @@
};

function webAuthnSign(webAuthnSignRequest) {
var publicKeyCredentialRequestOptions = {
const publicKeyCredentialRequestOptions = {
challenge: webAuthnBase64DecToArr(webAuthnSignRequest.challenge),
allowCredentials: webAuthnSignRequest.allowCredentials.map(function (x) {
return {
Expand All @@ -648,7 +669,7 @@
return Promise.reject();
}

var webAuthnSignResponse = {
const webAuthnSignResponse = {
credentialid: assertion.id,
clientdata: webAuthnBase64EncArr(assertion.response.clientDataJSON),
signaturedata: webAuthnBase64EncArr(assertion.response.signature),
Expand Down
1 change: 1 addition & 0 deletions privacyIDEAADFSProvider/FormResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ internal class FormResult
public string PasskeySignResponse { get; set; } = "";
public string PasskeyRegistrationResponse { get; set; } = "";
public string Origin { get; set; } = "";
public bool EnrollmentCancelled { get; set; } = false;
}
}
131 changes: 131 additions & 0 deletions privacyIDEAADFSProvider/PrivacyIDEA Client/PIConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
namespace PrivacyIDEAADFSProvider.PrivacyIDEA_Client
{
internal class PIConstants
{
// ENDPOINTS
public const string AUTH_ENDPOINT = "/auth";
public const string POLLTRANSACTION_ENDPOINT = "/validate/polltransaction";
public const string TRIGGERCHALLENGE_ENDPOINT = "/validate/triggerchallenge";
public const string VALIDATE_INITIALIZE_ENDPOINT = "/validate/initialize";
public const string TOKEN_ENDPOINT = "/token/";
public const string TOKEN_INIT_ENDPOINT = "/token/init";
public const string VALIDATE_CHECK_ENDPOINT = "/validate/check";
public const string POST = "POST";
public const string GET = "GET";

// SERVER RESPONSE
public const string RESULT = "result";
public const string STATUS = "status";
public const string ERROR = "error";
public const string CODE = "code";
public const string MESSAGE = "message";
public const string DETAIL = "detail";
public const string VALUE = "value";
public const string CHALLENGE = "challenge";
public const string SERIAL = "serial";
public const string TYPE = "type";
public const string TRANSACTION_ID = "transaction_id";
public const string IMAGE = "image";
public const string CLIENT_MODE = "client_mode";
public const string ATTRIBUTES = "attributes";
public const string GOOGLEURL = "googleurl";
public const string ALLOW_CREDENTIALS = "allowCredentials";
public const string AUTHENTICATION = "authentication";
public const string PREFERRED_CLIENT_MODE = "preferred_client_mode";
public const string INTERACTIVE = "interactive";
public const string POLL = "poll";
public const string PASSKEY = "passkey";
public const string PASSKEY_CHALLENGE = "passkey_challenge";
public const string MULTI_CHALLENGE = "multi_challenge";
public const string PASSKEY_REGISTRATION = "passkey_registration";
public const string LINK = "link";
public const string WEBAUTHNSIGNREQUEST = "webAuthnSignRequest";
public const string ENROLLMENT_VIA_MULTICHALLENGE = "enroll_via_multichallenge";
public const string ENROLLMENT_VIA_MULTICHALLENGE_OPTIONAL = "enroll_via_multichallenge_optional";
public const string CANCEL_ENROLLMENT = "cancel_enrollment";

// REQUEST PARAMETERS
public const string REALM = "realm";
public const string USERNAME = "username";
public const string PASS = "pass";
public const string OTP = "otp";
public const string USER = "user";
public const string GENKEY = "genkey";
public const string TOTP = "totp";
public const string ORIGIN = "Origin";
public const string PASSWORD = "password";
public const string USER_AGENT_HEADER = "User-Agent";

// TOKEN TYPES
public const string TOKEN_TYPE_OTP = "otp";
public const string TOKEN_TYPE_PUSH = "push";
public const string TOKEN_TYPE_PASSKEY = "passkey";
public const string TOKEN_TYPE_WEBAUTHN = "webauthn";

// FIDO2 PARAMETERS
public const string CREDENTIALID = "credentialId";
public const string CREDENTIAL_ID = "credential_id";
public const string CLIENTDATA = "clientdata";
public const string CLIENTDATAJSON = "clientdatajson";
public const string CLIENTDATAJSON_CAM = "clientDataJSON";
public const string SIGNATUREDATA = "signaturedata";
public const string SIGNATURE = "signature";
public const string AUTHENTICATORDATA = "authenticatordata";
public const string AUTHENTICATORDATA_CAM = "authenticatorData";
public const string USERHANDLE = "userhandle";
public const string USERHANDLE_CAM = "userHandle";
public const string RAW_ID = "raw_id";
public const string RAWID = "rawid";
public const string RAWID_CAM = "rawId";
public const string ASSERTIONCLIENTEXTENSIONS = "assertionclientextensions";
public const string AUTHENTICATORATTACHMENT = "authenticatorattachment";
public const string AUTHENTICATORATTACHMENT_CAM = "authenticatorAttachment";
public const string ATTESTATIONOBJECT = "attestationobject";
public const string ATTESTATIONOBJECT_CAM = "attestationObject";

public const string MEDIA_TYPE_URLENCODED = "application/x-www-form-urlencoded";

// ADAPTER
public const string NOT_USED = "not used";
public const string AUTH_SUCCESS = "authSuccess";
public const string USERID = "userid";
public const string DOMAIN = "domain";
public const string FORM_RESULT = "formResult";
public const string PUSH_AVAILABLE = "pushAvailable";
public const string TRANSACTIONID = "transactionid";
public const string CLIENT = "client";
public const string CLIENT_USER_AGENT = "client_user_agent";
public const string X_FORWARDED_FOR = "X-Forwarded-For";
public const string UNKNOWN = "unknown";
public const string PRIVACYIDEA_ADFS_USERAGENT = "PrivacyIDEA-ADFS/";
public const string DATE_FORMAT = "yyyy-MM-ddTHH\\:mm\\:ss;";
public const string EVENT_LOG_ADFS_ADMIN = "AD FS/Admin";
public const string EVENT_LOG_SOURCE = "privacyIDEAProvider";
public const string STREAM_WRITER_LOG = "C:\\PrivacyIDEA-ADFS log.txt";
public const string MS_SCHEMA_CLAIM_AUTHENTICATIONMETHOD = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod";
public const string MS_SCHEMA_AUTHMETHOD_OTP = "http://schemas.microsoft.com/ws/2012/12/authmethod/otp";

// FORM
public const string ENROLLMENT_IMG = "enrollmentImg";
public const string ENROLLMENT_LINK = "enrollmentLink";
public const string DISABLE_OTP = "disableOTP";
public const string AUTH_COUNTER = "authCounter";
public const string PREVIOUS_RESPONSE = "previousResponse";

// PASSKEY
public const string PASSKEY_REGISTRATION_SERIAL = "passkey_registration_serial";

// TOKEN'S TRANSACTION ID
public const string PUSH_TRANSACTION_ID = "push_transaction_id";
public const string WEBAUTHN_TRANSACTION_ID = "webauthn_transaction_id";
public const string PASSKEY_TRANSACTION_ID = "passkey_transaction_id";
public const string OTP_TRANSACTION_ID = "otp_transaction_id";

// MODE
public const string MODE = "mode";
public const string PUSH_MODE = "push";
public const string OTP_MODE = "otp";
public const string WEBAUTHN_MODE = "webauthn";
public const string PASSKEY_MODE = "passkey";
}
}
Loading