/// <summary> /// Trigger challenges for the given user using a service account. /// </summary> /// <param name="username">username to trigger challenges for</param> /// <param name="domain">optional domain which can be mapped to a privacyIDEA realm</param> /// <returns>PIResponse object or null on error</returns> public PIResponse TriggerChallenges(string username, string domain = null) { if (!GetAuthToken()) { Error("Unable to trigger challenges without an auth token!"); return(null); } var parameters = new Dictionary <string, string> { { "user", username } }; AddRealmForDomain(domain, parameters); string response = SendRequest("/validate/triggerchallenge", parameters); PIResponse ret = PIResponse.FromJSON(response, this); return(ret); }
/// <summary> /// Authenticate using the /validate/check endpoint with the username and OTP value. /// Optionally, a transaction id can be provided if authentication is done using challenge-response. /// </summary> /// <param name="user">username</param> /// <param name="otp">OTP</param> /// <param name="transactionid">optional transaction id to refer to a challenge</param> /// <param name="domain">optional domain which can be mapped to a privacyIDEA realm</param> /// <returns>PIResponse object or null on error</returns> public PIResponse ValidateCheck(string user, string otp, string transactionid = null, string domain = null) { var parameters = new Dictionary <string, string> { { "user", user }, { "pass", otp } }; if (transactionid != null) { parameters.Add("transaction_id", transactionid); } AddRealmForDomain(domain, parameters); string response = SendRequest("/validate/check", parameters, new List <KeyValuePair <string, string> >()); return(PIResponse.FromJSON(response, this)); }
/// <summary> /// Authenticate at the /validate/check endpoint using a WebAuthn token instead of the usual OTP value. /// This requires the WebAuthnSignResponse and the Origin from the browser. /// </summary> /// <param name="user">username</param> /// <param name="transactionid">transaction id of the webauthn challenge</param> /// <param name="webAuthnSignResponse">the WebAuthnSignResponse string in json format as returned from the browser</param> /// <param name="origin">origin also returned by the browser</param> /// <param name="domain">optional domain which can be mapped to a privacyIDEA realm</param> /// <returns>PIResponse object or null on error</returns> public PIResponse ValidateCheckWebAuthn(string user, string transactionid, string webAuthnSignResponse, string origin, string domain = null) { if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(transactionid) || string.IsNullOrEmpty(webAuthnSignResponse) || string.IsNullOrEmpty(origin)) { Log("ValidateCheckWebAuthn called with missing parameter: user="******", transactionid=" + transactionid + ", WebAuthnSignResponse=" + webAuthnSignResponse + ", origin=" + origin); return(null); } // Parse the WebAuthnSignResponse and add mandatory parameters JToken root; try { root = JToken.Parse(webAuthnSignResponse); } catch (JsonReaderException jex) { Error("WebAuthnSignRequest does not have the required format! " + jex.Message); return(null); } string credentialid = (string)root["credentialid"]; string clientdata = (string)root["clientdata"]; string signaturedata = (string)root["signaturedata"]; string authenticatordata = (string)root["authenticatordata"]; var parameters = new Dictionary <string, string> { { "user", user }, { "pass", "" }, { "transaction_id", transactionid }, { "credentialid", credentialid }, { "clientdata", clientdata }, { "signaturedata", signaturedata }, { "authenticatordata", authenticatordata } }; // Optionally add UserHandle and AssertionClientExtensions string userhandle = (string)root["userhandle"]; if (!string.IsNullOrEmpty(userhandle)) { parameters.Add("userhandle", userhandle); } string ace = (string)root["assertionclientextensions"]; if (!string.IsNullOrEmpty(ace)) { parameters.Add("assertionclientextensions", ace); } AddRealmForDomain(domain, parameters); // The origin has to be set in the header for WebAuthn authentication var headers = new List <KeyValuePair <string, string> > { new KeyValuePair <string, string>("Origin", origin) }; string response = SendRequest("/validate/check", parameters, headers); return(PIResponse.FromJSON(response, this)); }
public static PIResponse FromJSON(string json, PrivacyIDEA privacyIDEA) { if (string.IsNullOrEmpty(json)) { if (privacyIDEA != null) { privacyIDEA.Error("Json to parse is empty!"); } return(null); } PIResponse ret = new PIResponse(); ret.Raw = json; try { JObject jobj = JObject.Parse(json); JToken result = jobj["result"]; if (result != null) { ret.Status = (bool)result["status"]; JToken jVal = result["value"]; if (jVal != null) { ret.Value = (bool)jVal; } JToken error = result["error"]; if (error != null) { ret.ErrorCode = (int)error["code"]; ret.ErrorMessage = (string)error["message"]; } } JToken detail = jobj["detail"]; if (detail != null && detail.Type != JTokenType.Null) { ret.TransactionID = (string)detail["transaction_id"]; ret.Message = (string)detail["message"]; ret.Type = (string)detail["type"]; ret.Serial = (string)detail["serial"]; JArray multiChallenge = detail["multi_challenge"] as JArray; if (multiChallenge != null) { foreach (JToken element in multiChallenge.Children()) { string message = (string)element["message"]; string transactionid = (string)element["transaction_id"]; string type = (string)element["type"]; string serial = (string)element["serial"]; if (type == "webauthn") { PIWebAuthnSignRequest tmp = new PIWebAuthnSignRequest(); JToken attr = element["attributes"]; tmp.WebAuthnSignRequest = attr["webAuthnSignRequest"].ToString(Formatting.None); tmp.WebAuthnSignRequest.Replace("\n", ""); tmp.Message = message; tmp.Serial = serial; tmp.TransactionID = transactionid; tmp.Type = type; ret.Challenges.Add(tmp); } else { PIChallenge tmp = new PIChallenge(); tmp.Message = message; tmp.Serial = serial; tmp.TransactionID = transactionid; tmp.Type = type; ret.Challenges.Add(tmp); } } } } } catch (JsonException je) { if (privacyIDEA != null) { privacyIDEA.Error(je); } return(null); } return(ret); }