Skip to content

Commit e7b996c

Browse files
committed
feat: add custom auth plugin and related tests
1 parent d800e16 commit e7b996c

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

spec/acceptance/acceptance_tests.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,37 @@
148148
expect(body["status"]).to eq("success")
149149
end
150150
end
151+
152+
describe "custom auth plugin" do
153+
154+
it "successfully validates using a custom auth plugin" do
155+
payload = {}.to_json
156+
headers = { "Authorization" => "Bearer octoawesome-shared-secret" }
157+
response = http.post("/webhooks/with_custom_auth_plugin", payload, headers)
158+
159+
expect(response).to be_a(Net::HTTPSuccess)
160+
body = JSON.parse(response.body)
161+
expect(body["status"]).to eq("test_success")
162+
expect(body["handler"]).to eq("TestHandler")
163+
end
164+
165+
it "rejects requests with invalid credentials using custom auth plugin" do
166+
payload = {}.to_json
167+
headers = { "Authorization" => "Bearer wrong-secret" }
168+
response = http.post("/webhooks/with_custom_auth_plugin", payload, headers)
169+
170+
expect(response).to be_a(Net::HTTPUnauthorized)
171+
expect(response.body).to include("authentication failed")
172+
end
173+
174+
it "rejects requests with missing credentials using custom auth plugin" do
175+
payload = {}.to_json
176+
headers = {}
177+
response = http.post("/webhooks/with_custom_auth_plugin", payload, headers)
178+
179+
expect(response).to be_a(Net::HTTPUnauthorized)
180+
expect(response.body).to include("authentication failed")
181+
end
182+
end
151183
end
152184
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
path: /with_custom_auth_plugin
2+
handler: TestHandler
3+
4+
auth:
5+
type: example_auth_plugin
6+
secret_env_key: SHARED_SECRET # the name of the environment variable containing the shared secret
7+
header: Authorization
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
# this is just a super simple example of an auth plugin
4+
# it is not secure and should not be used in production
5+
# it is only for demonstration purposes
6+
7+
module Hooks
8+
module Plugins
9+
module Auth
10+
class ExampleAuthPlugin < Base
11+
def self.valid?(payload:, headers:, config:)
12+
# Get the secret from environment variable as configured with secret_env_key
13+
secret = fetch_secret(config, secret_env_key_name: :secret_env_key)
14+
15+
# Get the authorization header (case-insensitive)
16+
auth_header = nil
17+
headers.each do |key, value|
18+
if key.downcase == "authorization"
19+
auth_header = value
20+
break
21+
end
22+
end
23+
24+
# Check if the header matches our expected format
25+
return false unless auth_header
26+
27+
# Extract the token from "Bearer <token>" format
28+
return false unless auth_header.start_with?("Bearer ")
29+
30+
token = auth_header[7..-1] # Remove "Bearer " prefix
31+
32+
# Simple token comparison (in practice, this might be more complex)
33+
Rack::Utils.secure_compare(token, secret)
34+
rescue StandardError => e
35+
log.error("ExampleAuthPlugin failed: #{e.message}")
36+
false
37+
end
38+
end
39+
end
40+
end
41+
end

spec/acceptance/plugins/handlers/test_handler.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ class TestHandler < Hooks::Plugins::Handlers::Base
44
def call(payload:, headers:, config:)
55
{
66
status: "test_success",
7+
handler: "TestHandler",
78
payload_received: payload,
89
config_opts: config[:opts],
910
timestamp: Time.now.iso8601

0 commit comments

Comments
 (0)