blob: 65607ceec31d6f2e5a8333e00e4210597990fa6f [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/device_bound_sessions/registration_fetcher_param.h"
#include <optional>
#include "base/strings/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "crypto/signature_verifier.h"
#include "net/base/features.h"
#include "net/http/http_response_headers.h"
#include "net/http/structured_headers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net::device_bound_sessions {
namespace {
const char* GetRegistrationHeaderName() {
return net::features::kDeviceBoundSessionsOriginTrialFeedback.Get()
? "Secure-Session-Registration"
: "Sec-Session-Registration";
}
using crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
using crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
using ::testing::UnorderedElementsAre;
scoped_refptr<net::HttpResponseHeaders> CreateHeaders(
std::optional<std::string> path,
std::optional<std::string> algs,
std::optional<std::string> challenge,
std::optional<std::string> authorization,
scoped_refptr<net::HttpResponseHeaders> headers = nullptr) {
const std::string algs_string = (algs && !algs->empty()) ? *algs : "()";
const std::string path_string =
path ? base::StrCat({";path=\"", *path, "\""}) : "";
const std::string challenge_string =
challenge ? base::StrCat({";challenge=\"", *challenge, "\""}) : "";
std::string authorization_string;
if (authorization) {
authorization_string =
base::StrCat({";authorization=\"", *authorization, "\""});
}
const std::string full_string = base::StrCat(
{algs_string, path_string, challenge_string, authorization_string});
if (!headers) {
headers = HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
}
headers->AddHeader(GetRegistrationHeaderName(), full_string);
return headers;
}
TEST(RegistrationFetcherParamTest, BasicValid) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("startsession", "(ES256 RS256)", "c1", "auth");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "auth");
}
TEST(RegistrationFetcherParamTest, SubpathRequestUrlValid) {
const GURL registration_request(
"https://www.example.com/subpath/registration");
// Starting with a '/' to make it origin-relative.
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("/startsession", "(ES256 RS256)", "c1", "auth");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "auth");
}
TEST(RegistrationFetcherParamTest, ExtraUnrecognizedAlgorithm) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("startsession", "(ES256 bf512)", "c1", "auth");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "auth");
}
TEST(RegistrationFetcherParamTest, NoHeader) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, ChallengeFirst) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->SetHeader(
GetRegistrationHeaderName(),
"(RS256 ES256);challenge=\"challenge1\";path=\"first\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/first"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "challenge1");
}
TEST(RegistrationFetcherParamTest, NoSpaces) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->SetHeader(
GetRegistrationHeaderName(),
"(RS256 ES256);path=\"startsession\";challenge=\"challenge1\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "challenge1");
}
TEST(RegistrationFetcherParamTest, TwoRegistrations) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("/first", "(ES256 RS256)", "c1", "auth1");
CreateHeaders("/second", "(ES256)", "challenge2", "auth2", response_headers);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 2U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(), GURL("https://www.example.com/first"));
EXPECT_THAT(p1.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "c1");
EXPECT_EQ(p1.authorization(), "auth1");
const auto& p2 = params[1];
EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/second"));
EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p2.challenge(), "challenge2");
EXPECT_EQ(p2.authorization(), "auth2");
}
TEST(RegistrationFetcherParamTest, ValidInvalid) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/first", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
CreateHeaders("/second", "(es256)", "challenge2", "auth2", response_headers);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(), GURL("https://www.example.com/first"));
EXPECT_THAT(p1.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "c1");
EXPECT_FALSE(p1.authorization());
}
TEST(RegistrationFetcherParamTest, AddedInvalidNonsenseCharacters) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(GetRegistrationHeaderName(),
"(RS256);path=\"new\";challenge=\"test\";;=;");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, AddedValidNonsenseCharacters) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(RS256);path=\"new\";challenge=\"test\";nonsense=\";';'\",OTHER");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(), GURL("https://www.example.com/new"));
EXPECT_THAT(p1.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "test");
}
TEST(RegistrationFetcherParamTest, AlgAsString) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(GetRegistrationHeaderName(),
"(\"RS256\");path=\"new\";challenge=\"test\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, PathAsToken) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(GetRegistrationHeaderName(),
"(RS256);path=new;challenge=\"test\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, ChallengeAsByteSequence) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(GetRegistrationHeaderName(),
"(RS256);path=\"new\";challenge=:Y29kZWQ=:");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, ValidInvalidValid) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/first", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
CreateHeaders("/second", "(es256)", "challenge2", "auth2", response_headers);
CreateHeaders("/third", "(ES256)", "challenge3", "auth3", response_headers);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 2U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(), GURL("https://www.example.com/first"));
EXPECT_THAT(p1.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "c1");
EXPECT_FALSE(p1.authorization());
const auto& p2 = params[1];
EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/third"));
EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p2.challenge(), "challenge3");
EXPECT_EQ(p2.authorization(), "auth3");
}
TEST(RegistrationFetcherParamTest, ThreeRegistrations) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/startsession", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
CreateHeaders("/new", "(ES256)", "coded", "", response_headers);
CreateHeaders("/third", "(ES256)", "another", "auth", response_headers);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 3U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(p1.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "c1");
EXPECT_FALSE(p1.authorization());
const auto& p2 = params[1];
EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p2.challenge(), "coded");
EXPECT_EQ(p2.authorization(), "");
const auto& p3 = params[2];
EXPECT_EQ(p3.registration_endpoint(), GURL("https://www.example.com/third"));
EXPECT_THAT(p3.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p3.challenge(), "another");
EXPECT_EQ(p3.authorization(), "auth");
}
TEST(RegistrationFetcherParamTest, ThreeRegistrationsList) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/startsession", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
response_headers->AddHeader(GetRegistrationHeaderName(),
"(ES256);path=\"new\";challenge=\"coded\", "
"(ES256);path=\"third\";challenge=\"another\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 3U);
const auto& p1 = params[0];
EXPECT_EQ(p1.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(p1.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(p1.challenge(), "c1");
const auto& p2 = params[1];
EXPECT_EQ(p2.registration_endpoint(), GURL("https://www.example.com/new"));
EXPECT_THAT(p2.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p2.challenge(), "coded");
const auto& p3 = params[2];
EXPECT_EQ(p3.registration_endpoint(), GURL("https://www.example.com/third"));
EXPECT_THAT(p3.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(p3.challenge(), "another");
}
TEST(RegistrationFetcherParamTest, StartWithSlash) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/startsession", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, EscapeOnce) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"/%2561", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(), GURL("https://www.example.com/%61"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, InvalidUrl) {
const GURL registration_request = GURL("https://[/");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"new", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 0U);
}
TEST(RegistrationFetcherParamTest, NonSecureUrl) {
// HTTP is not allowed for the registration URL.
{
const GURL http_url("http://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("startsession", "(ES256 RS256)", "c1", "auth");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(http_url,
response_headers.get());
EXPECT_TRUE(params.empty());
}
// But localhost is okay.
{
const GURL localhost_url("http://localhost:8080/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("startsession", "(ES256 RS256)", "c1", "auth");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(localhost_url,
response_headers.get());
EXPECT_FALSE(params.empty());
}
}
TEST(RegistrationFetcherParamTest, HasUrlEncoded) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"test%2Fstart", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/test/start"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, FullUrl) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("https://accounts.example.com/startsession",
"(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://accounts.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, SwapAlgo) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"startsession", "(ES256 RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, OneAlgo) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers = CreateHeaders(
"startsession", "(RS256)", "c1", /*authorization=*/std::nullopt);
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
ASSERT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, InvalidParamIgnored) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->SetHeader(
GetRegistrationHeaderName(),
"(RS256);path=\"first\";challenge=\"c1\";another=true");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/first"));
ASSERT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, InvalidInputs) {
struct Input {
std::string request_url;
std::optional<std::string> path;
std::optional<std::string> algos;
std::optional<std::string> challenge;
};
const Input kInvalidInputs[] = {
// All invalid
{"https://www.example.com/reg", "", "()", ""},
// All missing
{"https://www.example.com/reg", std::nullopt, std::nullopt, std::nullopt},
// All valid different Url
{"https://www.example.com/registration",
"https://accounts.different.url/startsession", "(RS256)", "c1"},
// Empty request Url
{"", "start", "(RS256)", "c1"},
// Empty algo
{"https://www.example.com/reg", "start", "()", "c1"},
// Missing algo
{"https://www.example.com/reg", "start", std::nullopt, "c1"},
// Missing registration
{"https://www.example.com/reg", std::nullopt, "(ES256 RS256)", "c1"},
// Missing challenge
{"https://www.example.com/reg", "start", "(ES256 RS256)", std::nullopt},
// Empty challenge
{"https://www.example.com/reg", "start", "(ES256 RS256)", ""},
// Challenge invalid utf8
{"https://www.example.com/reg", "start", "(ES256 RS256)", "ab\xC0\x80"}};
for (const auto& input : kInvalidInputs) {
const GURL registration_request = GURL(input.request_url);
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders(input.path, input.algos, input.challenge,
/*authorization=*/std::nullopt);
SCOPED_TRACE(registration_request.spec() + "; " +
response_headers->raw_headers());
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
EXPECT_TRUE(params.empty());
}
}
TEST(RegistrationFetcherParamTest, ValidAuthorization) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
CreateHeaders("startsession", "(ES256 RS256)", "c1", "authcode");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(),
UnorderedElementsAre(ECDSA_SHA256, RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "authcode");
}
TEST(RegistrationFetcherParamTest, InvalidAuthorizationIgnored) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(RS256);path=\"startsession\";challenge=\"c1\";authorization=123");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_FALSE(param.authorization());
}
TEST(RegistrationFetcherParamTest, MultipleAuthorizationHeaders) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(RS256);path=\"startsession\";challenge=\"c1\";"
"authorization=\"auth1\";authorization=\"auth2\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "auth2");
}
TEST(RegistrationFetcherParamTest, MultipleAuthorizationHeadersWithEmpty) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(GetRegistrationHeaderName(),
"(RS256);path=\"startsession\";challenge=\"c1\";"
"authorization=\"auth1\";authorization=\"\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "");
}
TEST(RegistrationFetcherParamTest, EmptyStringAuthorization) {
const GURL registration_request("https://www.example.com/registration");
// Testing customized header.
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(RS256);path=\"startsession\";challenge=\"c1\";authorization=\"\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(RSA_PKCS1_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.authorization(), "");
}
TEST(RegistrationFetcherParamTest, ValidProviderParams) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(ES256);path=\"startsession\";challenge=\"c1\";provider_key=\"key\";"
"provider_url=\"https://"
"provider.example.com\";provider_session_id=\"id\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
ASSERT_EQ(params.size(), 1U);
const auto& param = params[0];
EXPECT_EQ(param.registration_endpoint(),
GURL("https://www.example.com/startsession"));
EXPECT_THAT(param.supported_algos(), UnorderedElementsAre(ECDSA_SHA256));
EXPECT_EQ(param.challenge(), "c1");
EXPECT_EQ(param.provider_key(), "key");
EXPECT_EQ(param.provider_url(), GURL("https://provider.example.com"));
EXPECT_EQ(param.provider_session_id(), Session::Id("id"));
}
TEST(RegistrationFetcherParamTest, IncompleteProviderParams) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(ES256);path=\"startsession\";challenge=\"c1\";provider_key=\"key\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
EXPECT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, IncompleteProviderParams2) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(ES256);path=\"startsession\";challenge=\"c1\";"
"provider_key=\"key\";provider_session_id=\"id\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
EXPECT_TRUE(params.empty());
}
TEST(RegistrationFetcherParamTest, InvalidProviderUrl) {
const GURL registration_request("https://www.example.com/registration");
scoped_refptr<net::HttpResponseHeaders> response_headers =
HttpResponseHeaders::Builder({1, 1}, "200 OK").Build();
response_headers->AddHeader(
GetRegistrationHeaderName(),
"(ES256);path=\"startsession\";challenge=\"c1\";provider_key=\"key\";"
"provider_url=\"http://"
"provider.example.com\";provider_session_id=\"id\"");
std::vector<RegistrationFetcherParam> params =
RegistrationFetcherParam::CreateIfValid(registration_request,
response_headers.get());
// The provider_url is not secure, so reject the federated registration
// request.
EXPECT_TRUE(params.empty());
}
} // namespace
} // namespace net::device_bound_sessions