From 8f9a6859e739522119b6f5ded629075eae28e9ba Mon Sep 17 00:00:00 2001 From: Adam Malcontenti-Wilson Date: Thu, 4 Apr 2019 11:44:22 -0700 Subject: [PATCH 1/3] Allow customisable auth path for all other auth methods --- lib/vault/api/auth.rb | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/vault/api/auth.rb b/lib/vault/api/auth.rb index 156c1945..3371d666 100644 --- a/lib/vault/api/auth.rb +++ b/lib/vault/api/auth.rb @@ -29,12 +29,13 @@ class Authenticate < Request # # @param [String] new_token # the new token to try to authenticate and store on the client - # + # @param [String] path (default: 'token') + # The path to the auth backend to use for the login procedure. # @return [Secret] - def token(new_token) + def token(new_token, path = 'token') old_token = client.token client.token = new_token - json = client.get("/v1/auth/token/lookup-self") + json = client.get("/v1/auth/#{CGI.escape(path)}/lookup-self") secret = Secret.decode(json) return secret rescue @@ -64,11 +65,12 @@ def token(new_token) # @param [Hash] options # additional options to pass to the authentication call, such as a custom # mount point - # + # @param [String] path (default: 'app-id') + # The path to the auth backend to use for the login procedure. # @return [Secret] - def app_id(app_id, user_id, options = {}) + def app_id(app_id, user_id, options = {}, path = 'app-id') payload = { app_id: app_id, user_id: user_id }.merge(options) - json = client.post("/v1/auth/app-id/login", JSON.fast_generate(payload)) + json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload)) secret = Secret.decode(json) client.token = secret.auth.client_token return secret @@ -87,12 +89,13 @@ def app_id(app_id, user_id, options = {}) # @param [String] role_id # @param [String] secret_id (default: nil) # It is required when `bind_secret_id` is enabled for the specified role_id - # + # @param [String] path (default: 'approle') + # The path to the auth backend to use for the login procedure. # @return [Secret] - def approle(role_id, secret_id=nil) + def approle(role_id, secret_id=nil, path='approle') payload = { role_id: role_id } payload[:secret_id] = secret_id if secret_id - json = client.post("/v1/auth/approle/login", JSON.fast_generate(payload)) + json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload)) secret = Secret.decode(json) client.token = secret.auth.client_token return secret @@ -113,11 +116,12 @@ def approle(role_id, secret_id=nil) # @param [Hash] options # additional options to pass to the authentication call, such as a custom # mount point - # + # @param [String] path (default: 'userpass') + # The path to the auth backend to use for the login procedure. # @return [Secret] - def userpass(username, password, options = {}) + def userpass(username, password, options = {}, path = 'userpass') payload = { password: password }.merge(options) - json = client.post("/v1/auth/userpass/login/#{encode_path(username)}", JSON.fast_generate(payload)) + json = client.post("/v1/auth/#{CGI.escape(path)}/login/#{encode_path(username)}", JSON.fast_generate(payload)) secret = Secret.decode(json) client.token = secret.auth.client_token return secret @@ -135,11 +139,12 @@ def userpass(username, password, options = {}) # @param [Hash] options # additional options to pass to the authentication call, such as a custom # mount point - # + # @param [String] path (default: 'ldap') + # The path to the auth backend to use for the login procedure. # @return [Secret] - def ldap(username, password, options = {}) + def ldap(username, password, options = {}, path = 'ldap') payload = { password: password }.merge(options) - json = client.post("/v1/auth/ldap/login/#{encode_path(username)}", JSON.fast_generate(payload)) + json = client.post("/v1/auth/#{CGI.escape(path)}/login/#{encode_path(username)}", JSON.fast_generate(payload)) secret = Secret.decode(json) client.token = secret.auth.client_token return secret @@ -255,7 +260,7 @@ def aws_iam(role, credentials_provider, iam_auth_header_value = nil, sts_endpoin # @param [String] role # @param [String] jwt # jwt returned by the instance identity metadata, or iam api - # @param [String] path optional + # @param [String] path (default: 'gcp') # the path were the gcp auth backend is mounted # # @return [Secret] From cf607d621ae01d82041e90fded7e3d8ff71282c3 Mon Sep 17 00:00:00 2001 From: Adam Malcontenti-Wilson Date: Thu, 4 Apr 2019 16:08:23 -0700 Subject: [PATCH 2/3] Convert path to keyword arg --- lib/vault/api/auth.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/vault/api/auth.rb b/lib/vault/api/auth.rb index 3371d666..ad8444fd 100644 --- a/lib/vault/api/auth.rb +++ b/lib/vault/api/auth.rb @@ -32,7 +32,7 @@ class Authenticate < Request # @param [String] path (default: 'token') # The path to the auth backend to use for the login procedure. # @return [Secret] - def token(new_token, path = 'token') + def token(new_token, path: 'token') old_token = client.token client.token = new_token json = client.get("/v1/auth/#{CGI.escape(path)}/lookup-self") @@ -68,7 +68,7 @@ def token(new_token, path = 'token') # @param [String] path (default: 'app-id') # The path to the auth backend to use for the login procedure. # @return [Secret] - def app_id(app_id, user_id, options = {}, path = 'app-id') + def app_id(app_id, user_id, path: 'app-id', **options) payload = { app_id: app_id, user_id: user_id }.merge(options) json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload)) secret = Secret.decode(json) @@ -92,7 +92,7 @@ def app_id(app_id, user_id, options = {}, path = 'app-id') # @param [String] path (default: 'approle') # The path to the auth backend to use for the login procedure. # @return [Secret] - def approle(role_id, secret_id=nil, path='approle') + def approle(role_id, secret_id=nil, path: 'approle') payload = { role_id: role_id } payload[:secret_id] = secret_id if secret_id json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload)) @@ -119,7 +119,7 @@ def approle(role_id, secret_id=nil, path='approle') # @param [String] path (default: 'userpass') # The path to the auth backend to use for the login procedure. # @return [Secret] - def userpass(username, password, options = {}, path = 'userpass') + def userpass(username, password, path: 'userpass', **options) payload = { password: password }.merge(options) json = client.post("/v1/auth/#{CGI.escape(path)}/login/#{encode_path(username)}", JSON.fast_generate(payload)) secret = Secret.decode(json) @@ -142,7 +142,7 @@ def userpass(username, password, options = {}, path = 'userpass') # @param [String] path (default: 'ldap') # The path to the auth backend to use for the login procedure. # @return [Secret] - def ldap(username, password, options = {}, path = 'ldap') + def ldap(username, password, path: 'ldap', **options) payload = { password: password }.merge(options) json = client.post("/v1/auth/#{CGI.escape(path)}/login/#{encode_path(username)}", JSON.fast_generate(payload)) secret = Secret.decode(json) @@ -264,7 +264,7 @@ def aws_iam(role, credentials_provider, iam_auth_header_value = nil, sts_endpoin # the path were the gcp auth backend is mounted # # @return [Secret] - def gcp(role, jwt, path = 'gcp') + def gcp(role, jwt, path: 'gcp') payload = { role: role, jwt: jwt } json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload)) secret = Secret.decode(json) @@ -292,7 +292,7 @@ def gcp(role, jwt, path = 'gcp') # The path to the auth backend to use for the login procedure. # # @return [Secret] - def tls(pem = nil, path = 'cert') + def tls(pem = nil, path: 'cert') new_client = client.dup new_client.ssl_pem_contents = pem if !pem.nil? From 9e5ee9a2f92f268adf3529f709960a6d724f27f5 Mon Sep 17 00:00:00 2001 From: Adam Malcontenti-Wilson Date: Fri, 5 Apr 2019 10:49:19 -0700 Subject: [PATCH 3/3] Add tests for custom path option --- lib/vault/api/auth.rb | 7 ++--- spec/integration/api/auth_spec.rb | 50 +++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/lib/vault/api/auth.rb b/lib/vault/api/auth.rb index ad8444fd..46396acb 100644 --- a/lib/vault/api/auth.rb +++ b/lib/vault/api/auth.rb @@ -29,13 +29,12 @@ class Authenticate < Request # # @param [String] new_token # the new token to try to authenticate and store on the client - # @param [String] path (default: 'token') - # The path to the auth backend to use for the login procedure. + # # @return [Secret] - def token(new_token, path: 'token') + def token(new_token) old_token = client.token client.token = new_token - json = client.get("/v1/auth/#{CGI.escape(path)}/lookup-self") + json = client.get("/v1/auth/token/lookup-self") secret = Secret.decode(json) return secret rescue diff --git a/spec/integration/api/auth_spec.rb b/spec/integration/api/auth_spec.rb index 6a380789..9a9d30d1 100644 --- a/spec/integration/api/auth_spec.rb +++ b/spec/integration/api/auth_spec.rb @@ -33,10 +33,6 @@ module Vault vault_test_client.sys.enable_auth("app-id", "app-id", nil) vault_test_client.logical.write("auth/app-id/map/app-id/#{@app_id}", { value: "default" }) vault_test_client.logical.write("auth/app-id/map/user-id/#{@user_id}", { value: @app_id }) - - vault_test_client.sys.enable_auth("new-app-id", "app-id", nil) - vault_test_client.logical.write("auth/new-app-id/map/app-id/#{@app_id}", { value: "default" }) - vault_test_client.logical.write("auth/new-app-id/map/user-id/#{@user_id}", { value: @app_id }) end before do @@ -48,8 +44,14 @@ module Vault expect(subject.token).to eq(result.auth.client_token) end - it "authenticates with custom options" do - result = subject.auth.app_id(@app_id, @user_id, mount: "new-app-id") + it "authenticates with custom path" do + @user_id = "89e2f7c1-7a4a-45ce-88ac-846b6cd4c80a" + + vault_test_client.sys.enable_auth("new-app-id", "app-id", nil) + vault_test_client.logical.write("auth/new-app-id/map/app-id/#{@app_id}", { value: "default" }) + vault_test_client.logical.write("auth/new-app-id/map/user-id/#{@user_id}", { value: @app_id }) + + result = subject.auth.app_id(@app_id, @user_id, path: "new-app-id") expect(subject.token).to eq(result.auth.client_token) end @@ -92,6 +94,15 @@ module Vault expect(subject.token).to eq(result.auth.client_token) end + it "authenticates with custom path" do + pending "approle does not support custom paths to enable approle on dev server" + + vault_test_client.sys.enable_auth("new-approle", "approle", nil) + + result = subject.auth.approle(@role_id, @secret_id, path: 'new-approle') + expect(subject.token).to eq(result.auth.client_token) + end + it "raises an error if the authentication is bad" do expect { expect { @@ -129,9 +140,6 @@ module Vault vault_test_client.sys.enable_auth("userpass", "userpass", nil) vault_test_client.logical.write("auth/userpass/users/#{@username}", { password: @password, policies: "default" }) - - vault_test_client.sys.enable_auth("new-userpass", "userpass", nil) - vault_test_client.logical.write("auth/new-userpass/users/#{@username}", { password: @password, policies: "default" }) end before do @@ -143,8 +151,13 @@ module Vault expect(subject.token).to eq(result.auth.client_token) end - it "authenticates with custom options" do - result = subject.auth.userpass(@username, @password, mount: "new-userpass") + it "authenticates with custom path" do + @password = @password.reverse # to ensure we don't match the default path auth + + vault_test_client.sys.enable_auth("new-userpass", "userpass", nil) + vault_test_client.logical.write("auth/new-userpass/users/#{@username}", { password: @password, policies: "default" }) + + result = subject.auth.userpass(@username, @password, path: "new-userpass") expect(subject.token).to eq(result.auth.client_token) end @@ -202,6 +215,19 @@ module Vault expect(subject.token).to eq(result.auth.client_token) end + it "authenticates with custom path" do + pending "dev server does not support tls" + pending "auth_tls does not support custom path" + + vault_test_client.sys.enable_auth("new-cert", "cert", nil) + + subject.auth_tls.set_certificate("kaelumania", certificate) + subject.ssl_pem_file = auth_cert + + result = subject.auth.tls(path: 'new-cert') + expect(subject.token).to eq(result.auth.client_token) + end + it "raises an error if the authentication is bad", vault: "> 0.6.1" do subject.sys.disable_auth("cert") @@ -243,7 +269,7 @@ module Vault ).and_call_original ) expect do - subject.auth.aws_iam('a_rolename', credentials_provider, 'mismatched_iam_header', 'https://sts.cn-north-1.amazonaws.com.cn') + subject.auth.aws_iam('a_rolename', credentials_provider, 'mismatched_iam_header', 'https://sts.cn-north-1.amazonaws.com.cn') end.to raise_error(Vault::HTTPClientError, /expected iam_header_canary but got mismatched_iam_header/) end