Skip to content

Commit 37bc023

Browse files
authored
Support a human readable title in OIDC policies (#1136)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent f13abdd commit 37bc023

8 files changed

Lines changed: 73 additions & 3 deletions

File tree

docs/configuration.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ follows is signed with a secret of the instance's own, unrelated to the provider
534534

535535
| Property | Type | Required | Default | Description |
536536
|-----------------|------|----------|---------|-------------|
537+
| `/title` | String | No | The policy name | A human readable version of the policy name |
537538
| `/issuer` | String | :red_circle: **Yes** | N/A | The OpenID Connect issuer to trust, matched against the identity token's `iss` claim and used to discover the provider's metadata, including the signing key set that verifies tokens |
538539
| `/clientId` | String | :red_circle: **Yes** | N/A | The client identifier registered with the provider for this instance |
539540
| `/clientSecret` | Object | :red_circle: **Yes** | N/A | The client secret shared with the provider, read from an environment variable so that it never lives in the configuration file |
@@ -559,6 +560,7 @@ sign in through their identity provider to reach it:
559560
{
560561
"type": "oidc",
561562
"name": "console",
563+
"title": "Acme Single Sign-On",
562564
"paths": [ "/console" ],
563565
"issuer": "https://accounts.example.com",
564566
"clientId": "schemas-registry",

src/configuration/include/sourcemeta/one/configuration.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ struct Configuration {
6868
Type type{Type::ApiKey};
6969
// The policy name
7070
sourcemeta::core::JSON::String name;
71+
// A human readable version of the name
72+
sourcemeta::core::JSON::String title;
7173
std::vector<sourcemeta::core::JSON::String> paths;
7274
Algorithm algorithm{Algorithm::Identity};
7375
// Environment variable names holding the keys

src/configuration/parse.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ auto Configuration::parse(const sourcemeta::core::JSON &data,
147147
for (const auto &entry : data.at("authentication").as_array()) {
148148
Configuration::AuthenticationEntry parsed;
149149
parsed.name = entry.at("name").to_string();
150+
parsed.title = parsed.name;
150151
for (const auto &path : entry.at("paths").as_array()) {
151152
parsed.paths.push_back(path.to_string());
152153
}
@@ -176,6 +177,10 @@ auto Configuration::parse(const sourcemeta::core::JSON &data,
176177
entry.at("clientSecret").at("environmentVariable").to_string();
177178
parsed.session_secret_variable =
178179
entry.at("sessionSecret").at("environmentVariable").to_string();
180+
const auto *title{entry.try_at("title")};
181+
if (title != nullptr) {
182+
parsed.title = title->to_string();
183+
}
179184
} else {
180185
parsed.type = Configuration::AuthenticationEntry::Type::ApiKey;
181186
parsed.algorithm =

src/configuration/schema/configuration.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"type": "string",
196196
"pattern": "^[a-z0-9-]+$"
197197
},
198+
"title": {
199+
"type": "string",
200+
"minLength": 1
201+
},
198202
"paths": {
199203
"type": "array",
200204
"minItems": 1,

test/cli/index/enterprise/fail-authentication-apikey-without-keys.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ The object value was expected to validate against the defined properties subsche
3333
The value was expected to be an object that defines properties "algorithms", "audience", "issuer", "name", "paths", and "type"
3434
at instance location "/authentication/0"
3535
at evaluate path "/properties/authentication/items/anyOf/1/required"
36-
The object value was expected to only define properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type", but it also defines properties "algorithm", and "keys"
36+
The value was expected to be an object that defines properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type"
3737
at instance location "/authentication/0"
3838
at evaluate path "/properties/authentication/items/anyOf/2/required"
3939
The object value was expected to validate against at least one of the 3 given subschemas

test/cli/index/enterprise/fail-authentication-public-type.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ The object value was expected to validate against the defined properties subsche
5050
The value was expected to be an object that defines properties "algorithms", "audience", "issuer", "name", "paths", and "type"
5151
at instance location "/authentication/0"
5252
at evaluate path "/properties/authentication/items/anyOf/1/required"
53-
The object value was expected to only define properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type", but it also defines properties "algorithm", and "keys"
53+
The value was expected to be an object that defines properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type"
5454
at instance location "/authentication/0"
5555
at evaluate path "/properties/authentication/items/anyOf/2/required"
5656
The object value was expected to validate against at least one of the 3 given subschemas

test/cli/index/enterprise/fail-authentication-unknown-algorithm.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ The object value was expected to validate against the defined properties subsche
5050
The value was expected to be an object that defines properties "algorithms", "audience", "issuer", "name", "paths", and "type"
5151
at instance location "/authentication/0"
5252
at evaluate path "/properties/authentication/items/anyOf/1/required"
53-
The object value was expected to only define properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type", but it also defines properties "algorithm", and "keys"
53+
The value was expected to be an object that defines properties "clientId", "clientSecret", "issuer", "name", "paths", "sessionSecret", and "type"
5454
at instance location "/authentication/0"
5555
at evaluate path "/properties/authentication/items/anyOf/2/required"
5656
The object value was expected to validate against at least one of the 3 given subschemas

test/unit/configuration/configuration_test.cc

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ TEST(authentication_apikey_identity) {
828828
EXPECT_EQ(configuration.path, "/tmp/one.json");
829829
EXPECT_EQ(configuration.authentication.size(), 1);
830830
EXPECT_EQ(configuration.authentication.at(0).name, "internal");
831+
EXPECT_EQ(configuration.authentication.at(0).title, "internal");
831832
EXPECT_EQ(configuration.authentication.at(0).paths,
832833
(std::vector<sourcemeta::core::JSON::String>{"/internal"}));
833834
EXPECT_EQ(
@@ -857,6 +858,7 @@ TEST(authentication_jwt) {
857858
EXPECT_EQ(entry.type,
858859
sourcemeta::one::Configuration::AuthenticationEntry::Type::JWT);
859860
EXPECT_EQ(entry.name, "ci");
861+
EXPECT_EQ(entry.title, "ci");
860862
EXPECT_EQ(entry.paths,
861863
(std::vector<sourcemeta::core::JSON::String>{"/internal"}));
862864
EXPECT_EQ(entry.issuer, "https://acme.example.com");
@@ -915,6 +917,7 @@ TEST(authentication_oidc) {
915917
EXPECT_EQ(entry.type,
916918
sourcemeta::one::Configuration::AuthenticationEntry::Type::OIDC);
917919
EXPECT_EQ(entry.name, "employees");
920+
EXPECT_EQ(entry.title, "employees");
918921
EXPECT_EQ(entry.paths,
919922
(std::vector<sourcemeta::core::JSON::String>{"/internal"}));
920923
EXPECT_EQ(entry.issuer, "https://login.example.com");
@@ -927,6 +930,60 @@ TEST(authentication_oidc) {
927930
EXPECT_FALSE(entry.jwks_uri.has_value());
928931
}
929932

933+
TEST(authentication_oidc_with_title) {
934+
const auto raw_configuration{sourcemeta::core::parse_json(R"JSON({
935+
"url": "https://example.com",
936+
"authentication": [
937+
{
938+
"type": "oidc",
939+
"name": "employees",
940+
"title": "Acme Single Sign-On",
941+
"paths": [ "/internal" ],
942+
"issuer": "https://login.example.com",
943+
"clientId": "registry",
944+
"clientSecret": { "environmentVariable": "ONE_OIDC_CLIENT_SECRET" },
945+
"sessionSecret": { "environmentVariable": "ONE_OIDC_SESSION_SECRET" }
946+
}
947+
]
948+
})JSON")};
949+
const auto configuration{sourcemeta::one::Configuration::parse(
950+
raw_configuration, "/tmp/one.json", ".")};
951+
952+
EXPECT_EQ(configuration.authentication.size(), 1);
953+
const auto &entry{configuration.authentication.at(0)};
954+
EXPECT_EQ(entry.type,
955+
sourcemeta::one::Configuration::AuthenticationEntry::Type::OIDC);
956+
EXPECT_EQ(entry.name, "employees");
957+
EXPECT_EQ(entry.title, "Acme Single Sign-On");
958+
}
959+
960+
TEST(authentication_rejects_oidc_with_empty_title) {
961+
const auto raw_configuration{sourcemeta::core::parse_json(R"JSON({
962+
"url": "https://example.com",
963+
"authentication": [
964+
{
965+
"type": "oidc",
966+
"name": "employees",
967+
"title": "",
968+
"paths": [ "/internal" ],
969+
"issuer": "https://login.example.com",
970+
"clientId": "registry",
971+
"clientSecret": { "environmentVariable": "ONE_OIDC_CLIENT_SECRET" },
972+
"sessionSecret": { "environmentVariable": "ONE_OIDC_SESSION_SECRET" }
973+
}
974+
]
975+
})JSON")};
976+
try {
977+
sourcemeta::one::Configuration::parse(raw_configuration, "/tmp/one.json",
978+
".");
979+
FAIL();
980+
} catch (const sourcemeta::one::ConfigurationValidationError &error) {
981+
EXPECT_STREQ(error.what(), "Invalid configuration");
982+
} catch (...) {
983+
FAIL();
984+
}
985+
}
986+
930987
TEST(authentication_rejects_oidc_without_session_secret) {
931988
const auto raw_configuration{sourcemeta::core::parse_json(R"JSON({
932989
"url": "https://example.com",

0 commit comments

Comments
 (0)