示例#1
0
        /// <summary>
        /// Initiates a new authentication process and returns our form to the AD FS system.
        /// </summary>
        /// <param name="identityClaim">Claim information from the ADFS</param>
        /// <param name="request">The http request</param>
        /// <param name="authContext">The context for the authentication</param>
        /// <returns>new instance of IAdapterPresentationForm</returns>
        public IAdapterPresentation BeginAuthentication(Claim identityClaim, HttpListenerRequest request,
                                                        IAuthenticationContext authContext)
        {
            Log("BeginAuthentication: identityClaim: " + identityClaim.Value);

            string username, domain, upn = "";

            // separates the username from the domain
            string[] tmp = identityClaim.Value.Split('\\');

            if (tmp.Length > 1)
            {
                username = tmp[1];
                domain   = tmp[0];
                if (use_upn)
                {
                    // get UPN from sAMAccountName
                    Log("Getting UPN for user:"******" and domain: " + domain + "...");
                    PrincipalContext ctx  = new PrincipalContext(ContextType.Domain, domain);
                    UserPrincipal    user = UserPrincipal.FindByIdentity(ctx, username);
                    upn = user.UserPrincipalName;
                    Log("Found UPN: " + upn);
                }
                else
                {
                    upn = "not used";
                }
            }
            else
            {
                username = tmp[0];
                upn      = tmp[0];
                domain   = "";
            }

            Log("UPN value: " + upn + ", Domain value: " + domain);

            // use upn or sam as loginname attribute
            if (use_upn)
            {
                username = upn;
            }

            // Prepare the form
            var form = new AdapterPresentationForm();

            // trigger challenges with service account or empty pass if configured
            PIResponse response = null;

            if (privacyIDEA != null)
            {
                if (this.triggerChallenge)
                {
                    response = privacyIDEA.TriggerChallenges(username, domain);
                }
                else if (this.sendEmptyPassword)
                {
                    response = privacyIDEA.ValidateCheck(username, "", domain: domain);
                }
            }
            else
            {
                Error("privacyIDEA not initialized!");
            }

            // Evaluate the response for triggered token and prepare the form accordingly
            if (response != null)
            {
                if (response.Challenges.Count > 0)
                {
                    form = ExtractChallengeDataToForm(response, form, authContext);
                }
                else if (response.Value)
                {
                    // Success in step 1, carry this over to the second step so that step will be skipped
                    authContext.Data.Add("authSuccess", "1");
                    form.AutoSubmit = "1";
                }
                else
                {
                    if (!string.IsNullOrEmpty(response.ErrorMessage))
                    {
                        Error("Error in first step: " + response.ErrorMessage);
                        form.ErrorMessage = response.ErrorMessage;
                    }
                    else
                    {
                        Error("Sent something in first step and got failure without message");
                    }
                }
            }

            form.Mode = "otp";
            authContext.Data.Add("userid", username);
            authContext.Data.Add("domain", domain);

            // Perform optional user enrollment
            // If a challenge was triggered previously, checking if the user has a token is skipped
            if (enrollmentEnabled &&
                (response != null && string.IsNullOrEmpty(response.TransactionID) || (response == null)) &&
                !privacyIDEA.UserHasToken(username, domain))
            {
                PIEnrollResponse res = privacyIDEA.TokenInit(username, domain);
                if (enrollmentApps.Any())
                {
                    form.EnrollmentApps = enrollmentApps;
                }
                form.EnrollmentUrl = res.TotpUrl;
                form.EnrollmentImg = res.Base64TotpImage;
            }

            return(form);
        }
示例#2
0
        public void TriggerChallenges()
        {
            string authToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicmVhbG0iOiIiLCJub25jZSI6IjVjOTc4NWM5OWU" +
                               "4ZDVhODY5YzUzNGI5ZmY1MWFmNzI2ZjI5OTE2YmYiLCJyb2xlIjoiYWRtaW4iLCJhdXRodHlwZSI6InBhc3N3b3JkIiwiZXhwIjoxNTg5NDUwMzk0LC" +
                               "JyaWdodHMiOlsicG9saWN5ZGVsZXRlIiwic3RhdGlzdGljc19yZWFkIiwiYXVkaXRsb2ciLCJlbmFibGUiLCJ1c2VybGlzdCIsInVwZGF0ZXVzZXIiL" +
                               "CJhZGR1c2VyIiwiZW5yb2xsU1BBU1MiLCJjYWNvbm5lY3RvcndyaXRlIiwidW5hc3NpZ24iLCJkZWxldGV1c2VyIiwic2V0cGluIiwiZGlzYWJsZSIs" +
                               "ImVucm9sbFNTSEtFWSIsImZldGNoX2F1dGhlbnRpY2F0aW9uX2l0ZW1zIiwicHJpdmFjeWlkZWFzZXJ2ZXJfcmVhZCIsImdldHJhbmRvbSIsImVucm9" +
                               "sbFNNUyIsIm1yZXNvbHZlcndyaXRlIiwicmFkaXVzc2VydmVyX3dyaXRlIiwiaW1wb3J0dG9rZW5zIiwic2V0X2hzbV9wYXNzd29yZCIsImVucm9sbF" +
                               "JFTU9URSIsImVucm9sbFUyRiIsInByaXZhY3lpZGVhc2VydmVyX3dyaXRlIiwiZW5yb2xsUkFESVVTIiwiY29weXRva2VucGluIiwiZW5yb2xsRU1BS" +
                               "UwiLCJyZXNldCIsImNhY29ubmVjdG9yZGVsZXRlIiwiZW5yb2xsVkFTQ08iLCJlbnJvbGxSRUdJU1RSQVRJT04iLCJzZXQiLCJnZXRzZXJpYWwiLCJw" +
                               "ZXJpb2RpY3Rhc2tfcmVhZCIsImV2ZW50aGFuZGxpbmdfd3JpdGUiLCJtcmVzb2x2ZXJkZWxldGUiLCJyZXNvbHZlcmRlbGV0ZSIsInNtdHBzZXJ2ZXJ" +
                               "fd3JpdGUiLCJyYWRpdXNzZXJ2ZXJfcmVhZCIsImVucm9sbDRFWUVTIiwiZW5yb2xsUEFQRVIiLCJlbnJvbGxZVUJJQ08iLCJnZXRjaGFsbGVuZ2VzIi" +
                               "wibWFuYWdlc3Vic2NyaXB0aW9uIiwibG9zdHRva2VuIiwiZGVsZXRlIiwiZW5yb2xscGluIiwic21zZ2F0ZXdheV93cml0ZSIsImVucm9sbFBVU0giL" +
                               "CJlbnJvbGxNT1RQIiwibWFuYWdlX21hY2hpbmVfdG9rZW5zIiwic3lzdGVtX2RvY3VtZW50YXRpb24iLCJtYWNoaW5lbGlzdCIsInRyaWdnZXJjaGFs" +
                               "bGVuZ2UiLCJzdGF0aXN0aWNzX2RlbGV0ZSIsInJlc29sdmVyd3JpdGUiLCJjbGllbnR0eXBlIiwic2V0dG9rZW5pbmZvIiwiZW5yb2xsT0NSQSIsImF" +
                               "1ZGl0bG9nX2Rvd25sb2FkIiwiZW5yb2xsUFciLCJlbnJvbGxIT1RQIiwiZW5yb2xsVEFOIiwiZXZlbnRoYW5kbGluZ19yZWFkIiwiY29weXRva2VudX" +
                               "NlciIsInRva2VubGlzdCIsInNtdHBzZXJ2ZXJfcmVhZCIsImVucm9sbERBUExVRyIsInJldm9rZSIsImVucm9sbFRPVFAiLCJjb25maWdyZWFkIiwiY" +
                               "29uZmlnd3JpdGUiLCJzbXNnYXRld2F5X3JlYWQiLCJlbnJvbGxRVUVTVElPTiIsInRva2VucmVhbG1zIiwiZW5yb2xsVElRUiIsInBvbGljeXJlYWQi" +
                               "LCJtcmVzb2x2ZXJyZWFkIiwicGVyaW9kaWN0YXNrX3dyaXRlIiwicG9saWN5d3JpdGUiLCJyZXNvbHZlcnJlYWQiLCJlbnJvbGxDRVJUSUZJQ0FURSI" +
                               "sImFzc2lnbiIsImNvbmZpZ2RlbGV0ZSIsImVucm9sbFlVQklLRVkiLCJyZXN5bmMiXX0.HvP_hgA-UJFINXnwoBVmAurqcaaMmwM-AsD1S6chGIM";

            string webAuthnSignRequest = "{\n" +
                                         "            \"allowCredentials\": [\n" +
                                         "              {\n" +
                                         "                \"id\": \"83De8z_CNqogB6aCyKs6dWIqwpOpzVoNaJ74lgcpuYN7l-95QsD3z-qqPADqsFlPwBXCMqEPssq75kqHCMQHDA\",\n" +
                                         "                \"transports\": [\n" +
                                         "                  \"internal\",\n" +
                                         "                  \"nfc\",\n" +
                                         "                  \"ble\",\n" +
                                         "                  \"usb\"\n" +
                                         "                ],\n" +
                                         "                \"type\": \"public-key\"\n" +
                                         "              }\n" +
                                         "            ],\n" +
                                         "            \"challenge\": \"dHzSmZnAhxEq0szRWMY4EGg8qgjeBhJDjAPYKWfd2IE\",\n" +
                                         "            \"rpId\": \"office.netknights.it\",\n" +
                                         "            \"timeout\": 60000,\n" +
                                         "            \"userVerification\": \"preferred\"\n" +
                                         "          }\n";

            // Auth token response
            server.Given(
                Request.Create()
                .WithPath("/auth")
                .UsingPost()
                .WithBody("username=admin&password=admin")
                .WithHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
                )
            .RespondWith(
                Response.Create()
                .WithStatusCode(200)
                .WithBody("{\n" +
                          "    \"id\": 1,\n" +
                          "    \"jsonrpc\": \"2.0\",\n" +
                          "    \"result\": {\n" +
                          "        \"status\": true,\n" +
                          "        \"value\": {\n" +
                          "            \"log_level\": 20,\n" +
                          "            \"menus\": [\n" +
                          "                \"components\",\n" +
                          "                \"machines\"\n" +
                          "            ],\n" +
                          "            \"realm\": \"\",\n" +
                          "            \"rights\": [\n" +
                          "                \"policydelete\",\n" +
                          "                \"resync\"\n" +
                          "            ],\n" +
                          "            \"role\": \"admin\",\n" +
                          "            \"token\": \"" + authToken + "\",\n" +
                          "            \"username\": \"admin\",\n" +
                          "            \"logout_time\": 120,\n" +
                          "            \"default_tokentype\": \"hotp\",\n" +
                          "            \"user_details\": false,\n" +
                          "            \"subscription_status\": 0\n" +
                          "        }\n" +
                          "    },\n" +
                          "    \"time\": 1589446794.8502703,\n" +
                          "    \"version\": \"privacyIDEA 3.2.1\",\n" +
                          "    \"versionnumber\": \"3.2.1\",\n" +
                          "    \"signature\": \"rsa_sha256_pss:\"\n" +
                          "}"));

            // Trigger challenge response
            server
            .Given(
                Request.Create()
                .WithPath("/validate/triggerchallenge")
                .UsingPost()
                .WithBody("user=test")
                .WithHeader("Authorization", authToken)
                .WithHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
                )
            .RespondWith(
                Response.Create()
                .WithStatusCode(200)
                .WithBody("{\n" +
                          "  \"detail\": {\n" +
                          "    \"attributes\": null,\n" +
                          "    \"message\": \"Bitte geben Sie einen OTP-Wert ein: , Please confirm the authentication on your mobile device!\",\n" +
                          "    \"messages\": [\n" +
                          "      \"Bitte geben Sie einen OTP-Wert ein: \",\n" +
                          "      \"Please confirm the authentication on your mobile device!\"\n" +
                          "    ],\n" +
                          "    \"multi_challenge\": [\n" +
                          "      {\n" +
                          "        \"attributes\": null,\n" +
                          "        \"message\": \"Bitte geben Sie einen OTP-Wert ein: \",\n" +
                          "        \"serial\": \"OATH00020121\",\n" +
                          "        \"transaction_id\": \"02659936574063359702\",\n" +
                          "        \"type\": \"hotp\"\n" +
                          "      },\n" +
                          "      {\n" +
                          "        \"attributes\": null,\n" +
                          "        \"message\": \"Please confirm the authentication on your mobile device!\",\n" +
                          "        \"serial\": \"PIPU0001F75E\",\n" +
                          "        \"transaction_id\": \"02659936574063359702\",\n" +
                          "        \"type\": \"push\"\n" +
                          "      },\n" +
                          "      {\n" +
                          "        \"attributes\": {\n" +
                          "          \"hideResponseInput\": true,\n" +
                          "          \"img\": \"static/img/FIDO-U2F-Security-Key-444x444.png\",\n" +
                          "          \"webAuthnSignRequest\": " + webAuthnSignRequest +
                          "        },\n" +
                          "        \"message\": \"Please confirm with your WebAuthn token (Yubico U2F EE Serial 61730834)\",\n" +
                          "        \"serial\": \"WAN00025CE7\",\n" +
                          "        \"transaction_id\": \"16786665691788289392\",\n" +
                          "        \"type\": \"webauthn\"\n" +
                          "      }\n" +
                          "    ],\n" +
                          "    \"serial\": \"PIPU0001F75E\",\n" +
                          "    \"threadid\": 140040525666048,\n" +
                          "    \"transaction_id\": \"02659936574063359702\",\n" +
                          "    \"transaction_ids\": [\n" +
                          "      \"02659936574063359702\",\n" +
                          "      \"02659936574063359702\"\n" +
                          "    ],\n" +
                          "    \"type\": \"push\"\n" +
                          "  },\n" +
                          "  \"id\": 1,\n" +
                          "  \"jsonrpc\": \"2.0\",\n" +
                          "  \"result\": {\n" +
                          "    \"status\": true,\n" +
                          "    \"value\": false\n" +
                          "  },\n" +
                          "  \"time\": 1589360175.594304,\n" +
                          "  \"version\": \"privacyIDEA 3.2.1\",\n" +
                          "  \"versionnumber\": \"3.2.1\",\n" +
                          "  \"signature\": \"rsa_sha256_pss:AAAAAAAAAA\"\n" +
                          "}"));

            privacyIDEA.SetServiceAccount("admin", "admin");

            var resp = privacyIDEA.TriggerChallenges("test");

            Assert.IsNotNull(resp);
            Assert.AreEqual(false, resp.Value);
            Assert.AreEqual(true, resp.Status);
            Assert.AreEqual("02659936574063359702", resp.TransactionID);
            Assert.AreEqual("Bitte geben Sie einen OTP-Wert ein: , Please confirm the authentication on your mobile device!", resp.Message);

            Assert.IsTrue(resp.TriggeredTokenTypes().Contains("push"));
            Assert.IsTrue(resp.TriggeredTokenTypes().Contains("hotp"));
            Assert.IsTrue(resp.TriggeredTokenTypes().Contains("webauthn"));

            var c1 = resp.Challenges.Find(item => item.Type == "push");

            Assert.AreEqual("PIPU0001F75E", c1.Serial);
            Assert.AreEqual("Please confirm the authentication on your mobile device!", c1.Message);
            Assert.AreEqual(c1.Attributes.Count, 0);

            var c2 = resp.Challenges.Find(item => item.Type == "hotp");

            Assert.AreEqual("OATH00020121", c2.Serial);
            Assert.AreEqual("Bitte geben Sie einen OTP-Wert ein: ", c2.Message);
            Assert.AreEqual(c2.Attributes.Count, 0);

            var c3 = resp.Challenges.Find(item => item.Type == "webauthn");

            Assert.AreEqual("WAN00025CE7", c3.Serial);
            Assert.AreEqual("Please confirm with your WebAuthn token (Yubico U2F EE Serial 61730834)", c3.Message);
            var signRequest = resp.WebAuthnSignRequest();

            Assert.IsFalse(string.IsNullOrEmpty(signRequest));
            // The WebAuthnSignRequest returned by PIResponse is unformatted, therefore the formatting of
            // webAuthnSignRequest is removed aswell
            Assert.AreEqual(webAuthnSignRequest.Replace("\n", "").Replace(" ", ""), signRequest);
        }