// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/printing/oauth2/authorization_zone.h"
#include <memory>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chrome/browser/ash/printing/oauth2/constants.h"
#include "chrome/browser/ash/printing/oauth2/mock_client_ids_database.h"
#include "chrome/browser/ash/printing/oauth2/test_authorization_server.h"
#include "chromeos/printing/uri.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace ash {
namespace printing {
namespace oauth2 {
namespace {
class PrintingOAuth2AuthorizationZoneTest : public testing::Test {
public:
// Initializes Authorization Zone.
void CreateAuthorizationZone(const std::string& client_id) {
GURL auth_server_uri(authorization_server_uri_);
CHECK(auth_server_uri.is_valid());
EXPECT_CALL(client_ids_database_, FetchId)
.WillOnce([client_id](const GURL& url, StatusCallback callback) {
std::move(callback).Run(StatusCode::kOK, client_id);
});
authorization_zone_ = printing::oauth2::AuthorizationZone::Create(
server_.GetURLLoaderFactory(), auth_server_uri, &client_ids_database_);
}
// Simulates the authorization process in the internet browser. Returns the
// URL that the browser is redirected to at the end of the authorization
// process.
std::string SimulateAuthorization(const std::string& authorization_url,
const std::string& auth_code,
const std::string& scope) {
auto question_mark = authorization_url.find('?');
EXPECT_LT(question_mark, authorization_url.size());
const std::string auth_host_path =
authorization_url.substr(0, question_mark);
base::flat_map<std::string, std::string> params;
EXPECT_TRUE(ParseURLParameters(authorization_url.substr(question_mark + 1),
params));
EXPECT_EQ(params["scope"], scope);
return base::StrCat(
{printing::oauth2::kRedirectURI,
"?code=", base::EscapeUrlEncodedData(auth_code, true),
"&state=", base::EscapeUrlEncodedData(params["state"], true)});
}
std::string SimulateAuthorizationError(const std::string& authorization_url,
const std::string& error) {
auto question_mark = authorization_url.find('?');
EXPECT_LT(question_mark, authorization_url.size());
const std::string auth_host_path =
authorization_url.substr(0, question_mark);
base::flat_map<std::string, std::string> params;
EXPECT_TRUE(ParseURLParameters(authorization_url.substr(question_mark + 1),
params));
return base::StrCat(
{printing::oauth2::kRedirectURI,
"?error=", base::EscapeUrlEncodedData(error, true),
"&state=", base::EscapeUrlEncodedData(params["state"], true)});
}
// Simulates Metadata Request described in rfc8414, section 3.
void ProcessMetadataRequest() {
EXPECT_EQ("", server_.ReceiveGET(metadata_uri_));
auto fields = BuildMetadata(authorization_server_uri_, authorization_uri_,
token_uri_, registration_uri_);
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_OK, fields);
}
// Simulates Registration Request described in rfc7591, section 3.
void ProcessRegistrationRequest(const std::string& client_id) {
base::Value::Dict fields;
EXPECT_EQ("", server_.ReceivePOSTWithJSON(registration_uri_, fields));
fields.Set("client_id", client_id);
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_CREATED, fields);
}
// Simulates First Token Request described in rfc6749, sections 4.1.3-4 and 5.
void ProcessFirstTokenRequest(const std::string& auth_code,
const std::string& access_token,
const std::string& refresh_token) {
base::flat_map<std::string, std::string> params;
EXPECT_EQ("", server_.ReceivePOSTWithURLParams(token_uri_, params));
EXPECT_EQ(params["code"], auth_code);
base::Value::Dict fields;
fields.Set("access_token", access_token);
fields.Set("token_type", "bearer");
if (!refresh_token.empty()) {
fields.Set("refresh_token", refresh_token);
}
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_OK, fields);
}
// The same as ProcessFirstTokenRequest(...) but with an error response.
void ProcessFirstTokenRequestError(const std::string& auth_code,
const std::string& error) {
base::flat_map<std::string, std::string> params;
EXPECT_EQ("", server_.ReceivePOSTWithURLParams(token_uri_, params));
EXPECT_EQ(params["code"], auth_code);
base::Value::Dict fields;
fields.Set("error", error);
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_BAD_REQUEST, fields);
}
// Simulates Next Token Request described in rfc6749, section 6.
void ProcessNextTokenRequest(const std::string& current_refresh_token,
const std::string& access_token,
const std::string& new_refresh_token) {
base::flat_map<std::string, std::string> params;
EXPECT_EQ("", server_.ReceivePOSTWithURLParams(token_uri_, params));
EXPECT_EQ(params["refresh_token"], current_refresh_token);
base::Value::Dict fields;
fields.Set("access_token", access_token);
fields.Set("token_type", "bearer");
if (!new_refresh_token.empty()) {
fields.Set("refresh_token", new_refresh_token);
}
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_OK, fields);
}
// Simulates Token Exchange Request described in rfc8693, section 2.
void ProcessTokenExchangeRequest(const chromeos::Uri& ipp_endpoint,
const std::string& access_token,
const std::string& endpoint_access_token) {
base::flat_map<std::string, std::string> params;
EXPECT_EQ("", server_.ReceivePOSTWithURLParams(token_uri_, params));
EXPECT_EQ(params["resource"], ipp_endpoint.GetNormalized());
EXPECT_EQ(params["subject_token"], access_token);
base::Value::Dict fields;
fields.Set("access_token", endpoint_access_token);
fields.Set("issued_token_type",
"urn:ietf:params:oauth:token-type:access_token");
fields.Set("token_type", "bearer");
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_OK, fields);
}
// The same as ProcessTokenExchangeRequest(...) but with an error response.
void ProcessTokenExchangeRequestError(const chromeos::Uri& ipp_endpoint,
const std::string& access_token,
const std::string& error) {
base::flat_map<std::string, std::string> params;
EXPECT_EQ("", server_.ReceivePOSTWithURLParams(token_uri_, params));
EXPECT_EQ(params["resource"], ipp_endpoint.GetNormalized());
EXPECT_EQ(params["subject_token"], access_token);
base::Value::Dict fields;
fields.Set("error", error);
server_.ResponseWithJSON(net::HttpStatusCode::HTTP_BAD_REQUEST, fields);
}
protected:
const std::string authorization_server_uri_ = "https://example.com/path";
const std::string metadata_uri_ =
"https://example.com/.well-known/oauth-authorization-server/path";
const std::string authorization_uri_ = "https://example.com/authorization";
const std::string token_uri_ = "https://example.com/token";
const std::string registration_uri_ = "https://example.com/registration";
testing::NiceMock<MockClientIdsDatabase> client_ids_database_;
std::unique_ptr<printing::oauth2::AuthorizationZone> authorization_zone_;
FakeAuthorizationServer server_;
};
TEST_F(PrintingOAuth2AuthorizationZoneTest, InitializationOfRegisteredClient) {
CallbackResult cr;
CreateAuthorizationZone("clientID_abcd1234");
authorization_zone_->InitAuthorization("scope1 scope2 scope3",
BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
const std::string authorization_url = cr.data;
// Parse and verify the returned URL.
auto question_mark = authorization_url.find('?');
ASSERT_LT(question_mark, authorization_url.size());
const std::string auth_host_path = authorization_url.substr(0, question_mark);
base::flat_map<std::string, std::string> params;
ASSERT_TRUE(
ParseURLParameters(authorization_url.substr(question_mark + 1), params));
EXPECT_EQ(auth_host_path, authorization_uri_);
EXPECT_EQ(params["response_type"], "code");
EXPECT_EQ(params["response_mode"], "query");
EXPECT_EQ(params["client_id"], "clientID_abcd1234");
EXPECT_EQ(params["redirect_uri"], printing::oauth2::kRedirectURI);
EXPECT_EQ(params["scope"], "scope1 scope2 scope3");
EXPECT_FALSE(params["code_challenge"].empty());
EXPECT_EQ(params["code_challenge_method"], "S256");
EXPECT_FALSE(params["state"].empty());
}
TEST_F(PrintingOAuth2AuthorizationZoneTest,
InitializationOfUnregisteredClient) {
CallbackResult cr;
CreateAuthorizationZone("");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ProcessRegistrationRequest("clientID_!@#$");
EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
const std::string authorization_url = cr.data;
// Parse and verify the returned URL.
auto question_mark = authorization_url.find('?');
ASSERT_LT(question_mark, authorization_url.size());
const std::string auth_host_path = authorization_url.substr(0, question_mark);
base::flat_map<std::string, std::string> params;
ASSERT_TRUE(
ParseURLParameters(authorization_url.substr(question_mark + 1), params));
EXPECT_EQ(params["client_id"], "clientID_!@#$");
EXPECT_EQ(params.count("scope"), 0u);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, FirstAccessToken) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
auto resultant_url = SimulateAuthorization(cr.data, "auth_code_123", "");
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
ProcessFirstTokenRequest("auth_code_123", "access_TOKEN", "refresh_TOKEN");
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
EXPECT_TRUE(cr.data.empty());
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, AuthorizationFail) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
auto resultant_url = SimulateAuthorizationError(cr.data, "weird_problem");
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kAccessDenied);
// The error message contains "weird_problem".
EXPECT_NE(cr.data.find("weird_problem"), std::string::npos);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest,
AuthorizationInvalidResponseEmptyCode) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
// The URL the browser was redirected to has empty "code" param.
auto resultant_url = SimulateAuthorization(cr.data, "", "");
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kInvalidResponse);
// The error message contains "code".
EXPECT_NE(cr.data.find("code"), std::string::npos);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest,
AuthorizationInvalidResponseNoState) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
// The URL the browser was redirected to has missing "state" param.
std::string resultant_url = printing::oauth2::kRedirectURI;
resultant_url += "?code=authCode123";
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kInvalidResponse);
// The error message contains "state".
EXPECT_NE(cr.data.find("state"), std::string::npos);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, FirstAccessTokenFail) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
auto resultant_url = SimulateAuthorization(cr.data, "auth_code_123", "");
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
ProcessFirstTokenRequestError("auth_code_123", "my unknown error");
EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kAccessDenied);
// The error message contains "my unknown error".
EXPECT_NE(cr.data.find("my unknown error"), std::string::npos);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, TokenRefresh) {
CallbackResult cr;
chromeos::Uri ipp_endpoint("ipp://my.printer:1234/path");
CreateAuthorizationZone("clientID_!@#$");
authorization_zone_->InitAuthorization("", BindResult(cr));
ProcessMetadataRequest();
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
auto resultant_url = SimulateAuthorization(cr.data, "auth_code_123", "");
authorization_zone_->FinishAuthorization(GURL(resultant_url), BindResult(cr));
ProcessFirstTokenRequest("auth_code_123", "access_TOKEN", "refresh_TOKEN");
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
authorization_zone_->GetEndpointAccessToken(ipp_endpoint, "", BindResult(cr));
ProcessTokenExchangeRequest(ipp_endpoint, "access_TOKEN",
"endpoint_token_24$#D");
ASSERT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
authorization_zone_->MarkEndpointAccessTokenAsExpired(ipp_endpoint,
"endpoint_token_24$#D");
authorization_zone_->GetEndpointAccessToken(ipp_endpoint, "", BindResult(cr));
ProcessTokenExchangeRequestError(ipp_endpoint, "access_TOKEN",
"invalid_grant");
ProcessNextTokenRequest("refresh_TOKEN", "access_token2_w5%",
"refresh_token2_1dh");
ProcessTokenExchangeRequest(ipp_endpoint, "access_token2_w5%",
"endpoint_token2_E46h");
EXPECT_EQ(cr.status, printing::oauth2::StatusCode::kOK);
EXPECT_EQ(cr.data, "endpoint_token2_E46h");
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, ParallelRequestsWithScopes) {
CallbackResult cr_ia1;
CallbackResult cr_ia2;
CallbackResult cr_ia3;
chromeos::Uri ipp_endpoint_1("ipp://my.printer:1234/path");
chromeos::Uri ipp_endpoint_2("ipp://my.other_printer:123/path");
CreateAuthorizationZone("clientID");
authorization_zone_->InitAuthorization("scope0", BindResult(cr_ia1));
authorization_zone_->InitAuthorization("scope1 scope2", BindResult(cr_ia2));
authorization_zone_->InitAuthorization("scope2", BindResult(cr_ia3));
ProcessMetadataRequest();
ASSERT_EQ(cr_ia1.status, printing::oauth2::StatusCode::kOK);
ASSERT_EQ(cr_ia2.status, printing::oauth2::StatusCode::kOK);
ASSERT_EQ(cr_ia3.status, printing::oauth2::StatusCode::kOK);
auto auth_url_1 = SimulateAuthorization(cr_ia1.data, "auth_code_1", "scope0");
auto auth_url_2 =
SimulateAuthorization(cr_ia2.data, "auth_code_2", "scope1 scope2");
auto auth_url_3 = SimulateAuthorization(cr_ia3.data, "auth_code_3", "scope2");
authorization_zone_->FinishAuthorization(GURL(auth_url_3),
BindResult(cr_ia3));
authorization_zone_->FinishAuthorization(GURL(auth_url_1),
BindResult(cr_ia1));
authorization_zone_->FinishAuthorization(GURL(auth_url_2),
BindResult(cr_ia2));
ProcessFirstTokenRequest("auth_code_3", "acc_token_3", "ref_token_3");
ProcessFirstTokenRequest("auth_code_1", "acc_token_1", "ref_token_1");
ProcessFirstTokenRequest("auth_code_2", "acc_token_2", "ref_token_2");
ASSERT_EQ(cr_ia1.status, printing::oauth2::StatusCode::kOK);
ASSERT_EQ(cr_ia2.status, printing::oauth2::StatusCode::kOK);
ASSERT_EQ(cr_ia3.status, printing::oauth2::StatusCode::kOK);
authorization_zone_->GetEndpointAccessToken(ipp_endpoint_1, "scope0",
BindResult(cr_ia1));
authorization_zone_->GetEndpointAccessToken(ipp_endpoint_2, "scope1",
BindResult(cr_ia2));
authorization_zone_->GetEndpointAccessToken(ipp_endpoint_1, "scope2 scope1",
BindResult(cr_ia3));
ProcessTokenExchangeRequest(ipp_endpoint_1, "acc_token_1", "end_token_1");
ProcessTokenExchangeRequest(ipp_endpoint_2, "acc_token_2", "end_token_2");
// The third GetEndpointAccessToken(...) call used the first token as the
// first one.
EXPECT_EQ(cr_ia1.status, printing::oauth2::StatusCode::kOK);
EXPECT_EQ(cr_ia2.status, printing::oauth2::StatusCode::kOK);
EXPECT_EQ(cr_ia3.status, printing::oauth2::StatusCode::kOK);
EXPECT_EQ(cr_ia1.data, "end_token_1");
EXPECT_EQ(cr_ia2.data, "end_token_2");
EXPECT_EQ(cr_ia3.data, "end_token_1");
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, ParallelInitializations) {
CreateAuthorizationZone("clientID");
std::vector<CallbackResult> crs(kMaxNumberOfSessions + 1);
// Too many initializations. The oldest one is going to be rejected.
for (auto& cr : crs) {
authorization_zone_->InitAuthorization("scope", BindResult(cr));
}
EXPECT_EQ(crs[0].status, printing::oauth2::StatusCode::kTooManySessions);
ProcessMetadataRequest();
for (size_t i = 1; i < crs.size(); ++i) {
EXPECT_EQ(crs[i].status, printing::oauth2::StatusCode::kOK);
}
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, ParallelAuthorizations) {
CreateAuthorizationZone("clientID");
std::vector<CallbackResult> crs(kMaxNumberOfSessions + 1);
// Call the first InitAuthorization(...) to go through initialization.
authorization_zone_->InitAuthorization("", BindResult(crs[0]));
ProcessMetadataRequest();
ASSERT_EQ(crs[0].status, printing::oauth2::StatusCode::kOK);
// Call InitAuthorization(...) kMaxNumberOfSessions times.
for (size_t i = 1; i < crs.size(); ++i) {
authorization_zone_->InitAuthorization("", BindResult(crs[i]));
ASSERT_EQ(crs[i].status, printing::oauth2::StatusCode::kOK);
}
// Call all corresponding FinishAuthorization(...).
for (size_t i = 0; i < crs.size(); ++i) {
auto auth_url = SimulateAuthorization(
crs[i].data, "auth_code_" + base::NumberToString(i), "");
authorization_zone_->FinishAuthorization(GURL(auth_url),
BindResult(crs[i]));
}
// The first call to FinishAuthorization(...) failed because the pending
// authorization is missing (was removed as the oldest one). Other calls
// succeeded.
EXPECT_EQ(crs[0].status, printing::oauth2::StatusCode::kNoMatchingSession);
for (size_t i = 1; i < crs.size(); ++i) {
const std::string si = base::NumberToString(i);
ProcessFirstTokenRequest("auth_code_" + si, "acc_token_" + si,
"ref_token_" + si);
EXPECT_EQ(crs[i].status, printing::oauth2::StatusCode::kOK);
}
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, ParallelFirstTokenRequests) {
CreateAuthorizationZone("clientID");
std::vector<CallbackResult> crs(kMaxNumberOfSessions + 1);
// Complete the first authorization and get an endpoint access token.
authorization_zone_->InitAuthorization("scope0", BindResult(crs[0]));
ProcessMetadataRequest();
ASSERT_EQ(crs[0].status, printing::oauth2::StatusCode::kOK);
auto auth_url_0 = SimulateAuthorization(crs[0].data, "auth_code_0", "scope0");
authorization_zone_->FinishAuthorization(GURL(auth_url_0),
BindResult(crs[0]));
ProcessFirstTokenRequest("auth_code_0", "acc_token_0", "ref_token_0");
ASSERT_EQ(crs[0].status, printing::oauth2::StatusCode::kOK);
authorization_zone_->GetEndpointAccessToken(chromeos::Uri("ipp://whatever:1"),
"scope0", BindResult(crs[0]));
ProcessTokenExchangeRequest(chromeos::Uri("ipp://whatever:1"), "acc_token_0",
"xxx");
EXPECT_EQ(crs[0].status, printing::oauth2::StatusCode::kOK);
// Start kMaxNumberOfSessions other sessions (with different scope).
for (size_t i = 1; i < crs.size(); ++i) {
const std::string si = base::NumberToString(i);
authorization_zone_->InitAuthorization("", BindResult(crs[i]));
ASSERT_EQ(crs[i].status, printing::oauth2::StatusCode::kOK);
auto auth_url = SimulateAuthorization(crs[i].data, "auth_code_" + si, "");
authorization_zone_->FinishAuthorization(GURL(auth_url),
BindResult(crs[i]));
ProcessFirstTokenRequest("auth_code_" + si, "acc_token_" + si,
"ref_token_" + si);
EXPECT_EQ(crs[i].status, printing::oauth2::StatusCode::kOK);
}
// The first session was closed because it was the oldest one and max allowed
// number of sessions was reached.
authorization_zone_->GetEndpointAccessToken(chromeos::Uri("ipp://whatever:2"),
"scope0", BindResult(crs[0]));
EXPECT_EQ(crs[0].status, printing::oauth2::StatusCode::kAuthorizationNeeded);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, CancellationDuringInitialization) {
CreateAuthorizationZone("clientID");
CallbackResult cr_0;
CallbackResult cr_1;
// Try to start two sessions and cancel before the first response from the
// server returns.
authorization_zone_->InitAuthorization("scope0", BindResult(cr_0));
authorization_zone_->InitAuthorization("scope1", BindResult(cr_1));
authorization_zone_->MarkAuthorizationZoneAsUntrusted();
EXPECT_EQ(cr_0.status, StatusCode::kUntrustedAuthorizationServer);
EXPECT_EQ(cr_1.status, StatusCode::kUntrustedAuthorizationServer);
// Response from the server should not trigger anything.
ProcessMetadataRequest();
EXPECT_EQ(cr_0.status, StatusCode::kUntrustedAuthorizationServer);
EXPECT_EQ(cr_1.status, StatusCode::kUntrustedAuthorizationServer);
}
TEST_F(PrintingOAuth2AuthorizationZoneTest, CancelExistingSessions) {
CreateAuthorizationZone("clientID");
CallbackResult cr_0;
CallbackResult cr_1;
// Start two sessions and send request for the first access token.
authorization_zone_->InitAuthorization("scope0", BindResult(cr_0));
authorization_zone_->InitAuthorization("scope1", BindResult(cr_1));
ProcessMetadataRequest();
ASSERT_EQ(cr_0.status, printing::oauth2::StatusCode::kOK);
ASSERT_EQ(cr_1.status, printing::oauth2::StatusCode::kOK);
auto auth_url_0 = SimulateAuthorization(cr_0.data, "auth_code_0", "scope0");
auto auth_url_1 = SimulateAuthorization(cr_1.data, "auth_code_1", "scope1");
authorization_zone_->FinishAuthorization(GURL(auth_url_0), BindResult(cr_0));
authorization_zone_->FinishAuthorization(GURL(auth_url_1), BindResult(cr_1));
// Get the access token for the first session and ask for an endpoint access
// token.
ProcessFirstTokenRequest("auth_code_0", "acc_token_0", "ref_token_0");
ASSERT_EQ(cr_0.status, printing::oauth2::StatusCode::kOK);
authorization_zone_->GetEndpointAccessToken(chromeos::Uri("ipp://printer0"),
"scope0", BindResult(cr_0));
// Cancel the zone. All pending callbacks should return.
authorization_zone_->MarkAuthorizationZoneAsUntrusted();
EXPECT_EQ(cr_0.status, StatusCode::kUntrustedAuthorizationServer);
EXPECT_EQ(cr_1.status, StatusCode::kUntrustedAuthorizationServer);
}
} // namespace
} // namespace oauth2
} // namespace printing
} // namespace ash