diff --git a/CHANGELOG.md b/CHANGELOG.md index 457e68a..9c981bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ IMPROVEMENTS - Added `cluster_address` field to `LeaderStatus` response from `sys/leader` endpoint [GH-204] - Updated AppRole `set_role` documentation to include modern parameters like `secret_id_bound_cidrs`, `token_bound_cidrs`, and `token_policies`. Added reference to official Vault API docs for complete parameter list. [GH-220] +- Added support for custom mount paths in AppRole authentication via `mount:` option [GH-292] BUG FIXES diff --git a/lib/vault/api/auth.rb b/lib/vault/api/auth.rb index b90420e..0069aec 100644 --- a/lib/vault/api/auth.rb +++ b/lib/vault/api/auth.rb @@ -81,21 +81,32 @@ def app_id(app_id, user_id, options = {}) # successful, the resulting token will be stored on the client and used for # future requests. # - # @example + # @example Default mount point # Vault.auth.approle( # "db02de05-fa39-4855-059b-67221c5c2f63", # "6a174c20-f6de-a53c-74d2-6018fcceff64", # ) #=> # # + # @example Custom mount point + # Vault.auth.approle( + # "db02de05-fa39-4855-059b-67221c5c2f63", + # "6a174c20-f6de-a53c-74d2-6018fcceff64", + # mount: "my-approle" + # ) #=> # + # # @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 [Hash] options + # @option options [String] :mount (default: "approle") + # The path where the approle auth backend is mounted # # @return [Secret] - def approle(role_id, secret_id=nil) + def approle(role_id, secret_id=nil, options = {}) + mount = options[:mount] || 'approle' payload = { role_id: role_id } payload[:secret_id] = secret_id if secret_id - json = client.post("/v1/auth/approle/login", JSON.generate(payload)) + json = client.post("/v1/auth/#{CGI.escape(mount)}/login", JSON.generate(payload)) secret = Secret.decode(json) client.token = secret.auth.client_token return secret diff --git a/spec/integration/api/auth_spec.rb b/spec/integration/api/auth_spec.rb index f387bb6..cf1c0c1 100644 --- a/spec/integration/api/auth_spec.rb +++ b/spec/integration/api/auth_spec.rb @@ -86,6 +86,33 @@ module Vault expect(subject.token).to eq(result.auth.client_token) end end + + context "when using a custom mount path" do + before(:context) do + @custom_path = "custom-approle" + @custom_approle = "custom-role" + vault_test_client.sys.enable_auth(@custom_path, "approle", nil) + + # Use logical.write to configure the role on the custom mount + vault_test_client.logical.write("auth/#{@custom_path}/role/#{@custom_approle}", { + secret_id_ttl: "10m", + token_ttl: "20m", + }) + + @role_id = vault_test_client.logical.read("auth/#{@custom_path}/role/#{@custom_approle}/role-id").data[:role_id] + @secret_id = vault_test_client.logical.write("auth/#{@custom_path}/role/#{@custom_approle}/secret-id", {}).data[:secret_id] + end + + after(:context) do + vault_test_client.logical.delete("auth/#{@custom_path}/role/#{@custom_approle}") + vault_test_client.sys.disable_auth(@custom_path) + end + + it "authenticates using the custom mount path" do + result = subject.auth.approle(@role_id, @secret_id, mount: @custom_path) + expect(subject.token).to eq(result.auth.client_token) + end + end end describe "#userpass" do