Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support authorization url #228

Merged
merged 4 commits into from
Aug 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions include/api_manager/method.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ class MethodInfo {
const std::string &issuer,
const std::set<std::string> &jwt_audiences) const = 0;

// Return authorization url for an issuer if specified.
virtual const std::string &authorization_url_by_issuer(
const std::string &issuer) const = 0;
// Return the first authorization url for this method.
virtual const std::string &first_authorization_url() const = 0;

// Get http header system parameters by name.
virtual const std::vector<std::string> *http_header_parameters(
const std::string &name) const = 0;
Expand Down
3 changes: 3 additions & 0 deletions include/api_manager/request_handler_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class RequestHandlerInterface {

// Get the method info.
virtual const MethodCallInfo *method_call() const = 0;

// Return the authorization url if authentication fails.
virtual std::string GetAuthorizationUrl() const = 0;
};

} // namespace api_manager
Expand Down
2 changes: 1 addition & 1 deletion repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ cc_proto_library(

native.new_git_repository(
name = "googleapis_git",
commit = "cbf6dc5d95d497b621a5c0e35696355deff336af", # June 14, 2017
commit = "75c3a512bce1ac7c2e9a1dd8b2c38ac3f1f5697c", # July 21, 2017
remote = "https://github.com/googleapis/googleapis.git",
build_file_content = BUILD,
)
Expand Down
3 changes: 2 additions & 1 deletion src/api_manager/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,8 @@ bool Config::LoadAuthentication(ApiManagerEnvInterface *env) {
const std::string &audiences = provider->audiences().empty()
? requirement.audiences()
: provider->audiences();
(*method)->addAudiencesForIssuer(provider->issuer(), audiences);
(*method)->addAuthProvider(provider->issuer(), audiences,
provider->authorization_url());
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/api_manager/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ static const char auth_config[] =
" id: \"provider-id2\"\n"
" issuer: \"issuer2@gserviceaccount.com\"\n"
" jwks_uri: \"https://www.googleapis.com/jwks_uri2\"\n"
" authorization_url: \"https://www.googleapis.com/auth\"\n"
" }\n"
" providers {\n"
" id: \"esp-auth0\"\n"
Expand Down Expand Up @@ -371,6 +372,9 @@ TEST(Config, TestLoadAuthentication) {
{"ok_audience1"}));
ASSERT_FALSE(method1->isAudienceAllowed("issuer1@gserviceaccount.com",
{"ok_audience2"}));
EXPECT_EQ(method1->authorization_url_by_issuer("issuer1@gserviceaccount.com"),
"");
EXPECT_EQ(method1->first_authorization_url(), "");

const MethodInfo *method2 = config->GetMethodInfo("GET", "/xyz/method2/abc");
ASSERT_EQ("Xyz.Method2", method2->name());
Expand All @@ -381,6 +385,10 @@ TEST(Config, TestLoadAuthentication) {
{"ok_audience1"}));
ASSERT_TRUE(method2->isAudienceAllowed("issuer2@gserviceaccount.com",
{"ok_audience2"}));
EXPECT_EQ(method2->authorization_url_by_issuer("issuer2@gserviceaccount.com"),
"https://www.googleapis.com/auth");
EXPECT_EQ(method2->first_authorization_url(),
"https://www.googleapis.com/auth");

const MethodInfo *method3 = config->GetMethodInfo("GET", "/xyz/method3/abc");
ASSERT_EQ("Xyz.Method3", method3->name());
Expand Down
11 changes: 11 additions & 0 deletions src/api_manager/context/request_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,17 @@ void RequestContext::StartBackendSpanAndSetTraceContext() {
}
}

std::string RequestContext::GetAuthorizationUrl() const {
if (method_call_.method_info == nullptr) {
return "";
}
if (auth_issuer_.empty()) {
return method_call_.method_info->first_authorization_url();
} else {
return method_call_.method_info->authorization_url_by_issuer(auth_issuer_);
}
}

} // namespace context
} // namespace api_manager
} // namespace google
3 changes: 3 additions & 0 deletions src/api_manager/context/request_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class RequestContext {
// Get the auth claims.
const std::string &auth_claims() const { return auth_claims_; }

// Return the authorization url.
std::string GetAuthorizationUrl() const;

private:
// Fill OperationInfo
void FillOperationInfo(service_control::OperationInfo *info);
Expand Down
37 changes: 30 additions & 7 deletions src/api_manager/method_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,48 +43,71 @@ MethodInfoImpl::MethodInfoImpl(const string &name, const string &api_name,
request_streaming_(false),
response_streaming_(false) {}

void MethodInfoImpl::addAudiencesForIssuer(const string &issuer,
const string &audiences_list) {
void MethodInfoImpl::addAuthProvider(const std::string &issuer,
const string &audiences_list,
const std::string &authorization_url) {
if (issuer.empty()) {
return;
}
std::string iss = utils::GetUrlContent(issuer);
if (iss.empty()) {
return;
}
set<string> &audiences = issuer_audiences_map_[iss];
AuthProvider &provider = issuer_provider_map_[iss];
stringstream ss(audiences_list);
string audience;
// Audience list is comma-delimited.
while (getline(ss, audience, ',')) {
if (!audience.empty()) { // Only adds non-empty audience.
std::string aud = utils::GetUrlContent(audience);
if (!aud.empty()) {
audiences.insert(aud);
provider.audiences.insert(aud);
}
}
}
provider.authorization_url = authorization_url;
}

bool MethodInfoImpl::isIssuerAllowed(const std::string &issuer) const {
return !issuer.empty() &&
issuer_audiences_map_.find(issuer) != issuer_audiences_map_.end();
issuer_provider_map_.find(issuer) != issuer_provider_map_.end();
}

bool MethodInfoImpl::isAudienceAllowed(
const string &issuer, const std::set<string> &jwt_audiences) const {
if (issuer.empty() || jwt_audiences.empty() || !isIssuerAllowed(issuer)) {
return false;
}
const set<string> &audiences = issuer_audiences_map_.at(issuer);
const AuthProvider &provider = issuer_provider_map_.at(issuer);
for (const auto &it : jwt_audiences) {
if (audiences.find(it) != audiences.end()) {
if (provider.audiences.find(it) != provider.audiences.end()) {
return true;
}
}
return false;
}

const std::string &MethodInfoImpl::authorization_url_by_issuer(
const std::string &issuer) const {
const auto &it = issuer_provider_map_.find(issuer);
if (it != issuer_provider_map_.end()) {
return it->second.authorization_url;
} else {
static std::string empty;
return empty;
}
}

const std::string &MethodInfoImpl::first_authorization_url() const {
for (const auto &it : issuer_provider_map_) {
if (!it.second.authorization_url.empty()) {
return it.second.authorization_url;
}
}
static std::string empty;
return empty;
}

void MethodInfoImpl::process_system_parameters() {
api_key_http_headers_ = http_header_parameters(api_key_parameter_name);
api_key_url_query_parameters_ = url_query_parameters(api_key_parameter_name);
Expand Down
23 changes: 17 additions & 6 deletions src/api_manager/method_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class MethodInfoImpl : public MethodInfo {
bool isAudienceAllowed(const std::string &issuer,
const std::set<std::string> &jwt_audiences) const;

const std::string &authorization_url_by_issuer(
const std::string &issuer) const;

const std::string &first_authorization_url() const;

const std::vector<std::string> *http_header_parameters(
const std::string &name) const {
return utils::FindOrNull(http_header_parameters_, name);
Expand Down Expand Up @@ -80,10 +85,12 @@ class MethodInfoImpl : public MethodInfo {

bool response_streaming() const { return response_streaming_; }

// Adds allowed audiences (comma delimated, no space) for the issuer.
// audiences_list can be empty.
void addAudiencesForIssuer(const std::string &issuer,
const std::string &audiences_list);
// Add an auth provider info for the issuer.
// audiences_list can be empty or comma delimited without space.
void addAuthProvider(const std::string &issuer,
const std::string &audiences_list,
const std::string &authorization_url);

void set_auth(bool v) { auth_ = v; }
void set_allow_unregistered_calls(bool v) { allow_unregistered_calls_ = v; }
void set_skip_service_control(bool v) { skip_service_control_ = v; }
Expand Down Expand Up @@ -138,6 +145,10 @@ class MethodInfoImpl : public MethodInfo {
void ProcessSystemQueryParameterNames();

private:
struct AuthProvider {
std::set<std::string> audiences;
std::string authorization_url;
};
// Method name
std::string name_;
// API name
Expand All @@ -151,8 +162,8 @@ class MethodInfoImpl : public MethodInfo {
bool allow_unregistered_calls_;
// Should the method skip service control.
bool skip_service_control_;
// Issuers to allowed audiences map.
std::map<std::string, std::set<std::string>> issuer_audiences_map_;
// Issuers to auth provider map.
std::map<std::string, AuthProvider> issuer_provider_map_;

// system parameter map of parameter name to http_header name.
std::map<std::string, std::vector<std::string>> http_header_parameters_;
Expand Down
31 changes: 20 additions & 11 deletions src/api_manager/method_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,17 @@ TEST(MethodInfo, Create) {

TEST(MethodInfo, IssueAndAudiences) {
MethodInfoImplPtr method_info(new MethodInfoImpl(kMethodName, "", ""));
method_info->addAudiencesForIssuer(kIssuer1, "aud1,aud2");
method_info->addAudiencesForIssuer(kIssuer1, "aud3");
method_info->addAudiencesForIssuer(kIssuer1, ",");
method_info->addAudiencesForIssuer(kIssuer1, ",aud4");
method_info->addAudiencesForIssuer(kIssuer1, "");
method_info->addAudiencesForIssuer(kIssuer1, ",aud5,,,");
method_info->addAudiencesForIssuer(kIssuer2https, ",,,aud6");
method_info->addAudiencesForIssuer(kIssuer3http, "");
method_info->addAudiencesForIssuer(kIssuer3http, "https://aud7");
method_info->addAudiencesForIssuer(kIssuer3http, "http://aud8");
method_info->addAudiencesForIssuer(kIssuer3http, "https://aud9/");
method_info->addAuthProvider(kIssuer1, "aud1,aud2", "");
method_info->addAuthProvider(kIssuer1, "aud3", "");
method_info->addAuthProvider(kIssuer1, ",", "");
method_info->addAuthProvider(kIssuer1, ",aud4", "");
method_info->addAuthProvider(kIssuer1, "", "");
method_info->addAuthProvider(kIssuer1, ",aud5,,,", "");
method_info->addAuthProvider(kIssuer2https, ",,,aud6", "");
method_info->addAuthProvider(kIssuer3http, "", "");
method_info->addAuthProvider(kIssuer3http, "https://aud7", "");
method_info->addAuthProvider(kIssuer3http, "http://aud8", "");
method_info->addAuthProvider(kIssuer3http, "https://aud9/", "");

ASSERT_TRUE(method_info->isIssuerAllowed(kIssuer1));
ASSERT_TRUE(method_info->isIssuerAllowed(kIssuer2));
Expand Down Expand Up @@ -88,6 +88,15 @@ TEST(MethodInfo, IssueAndAudiences) {
ASSERT_FALSE(method_info->isAudienceAllowed(kIssuer1, {}));
}

TEST(MethodInfo, IssueAndAuthorizationUrl) {
MethodInfoImplPtr method_info(new MethodInfoImpl(kMethodName, "", ""));
method_info->addAuthProvider(kIssuer1, "", "url1");
method_info->addAuthProvider(kIssuer2, "aud1,aud2", "");
EXPECT_EQ(method_info->authorization_url_by_issuer(kIssuer1), "url1");
EXPECT_EQ(method_info->authorization_url_by_issuer(kIssuer2), "");
EXPECT_EQ(method_info->first_authorization_url(), "url1");
}

TEST(MethodInfo, TestParameters) {
MethodInfoImplPtr method_info(new MethodInfoImpl(kMethodName, "", ""));

Expand Down
4 changes: 4 additions & 0 deletions src/api_manager/request_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,9 @@ std::string RequestHandler::GetRpcMethodFullName() const {
}
}

std::string RequestHandler::GetAuthorizationUrl() const {
return context_->GetAuthorizationUrl();
}

} // namespace api_manager
} // namespace google
2 changes: 2 additions & 0 deletions src/api_manager/request_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class RequestHandler : public RequestHandlerInterface {
// Get the method info.
const MethodCallInfo *method_call() const { return context_->method_call(); }

virtual std::string GetAuthorizationUrl() const;

private:
// The context object needs to pass to the continuation function the check
// handler as a lambda capture so it can be passed to the next check handler.
Expand Down
10 changes: 10 additions & 0 deletions src/grpc/transcoding/transcoder_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ class TestMethodInfo : public MethodInfo {
bool response_streaming() const { return response_streaming_; }
const std::string &body_field_path() const { return body_field_path_; }

const std::string &authorization_url_by_issuer(
const std::string &issuer) const {
static std::string empty;
return empty;
}
const std::string &first_authorization_url() const {
static std::string empty;
return empty;
}

private:
std::string request_type_url_;
std::string response_type_url_;
Expand Down
Loading