Skip to content

Commit

Permalink
Add config to allow specifying public, non-authenticated routes
Browse files Browse the repository at this point in the history
  • Loading branch information
lauramosher committed Jan 4, 2023
1 parent 2e8f131 commit 7c4cad3
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 23 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added ability to specify public routes that do not require authentication.

## [0.2.0] - 2023-01-04

### Added
Expand Down
3 changes: 2 additions & 1 deletion lib/rack/firebase/configuration.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
module Rack
module Firebase
class Configuration
attr_accessor :project_ids
attr_accessor :project_ids, :public_routes

def initialize
reset!
end

def reset!
@project_ids = []
@public_routes = []
end
end
end
Expand Down
51 changes: 29 additions & 22 deletions lib/rack/firebase/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,37 @@ def initialize(app)
end

def call(env)
token = AuthorizationHeader.read_token(env)
decoded_token = TokenDecoder.new.call(token)
path = env.fetch("PATH_INFO", "no-match")
if config.public_routes.none? { |r| r.match(path) }
begin
token = AuthorizationHeader.read_token(env)
decoded_token = TokenDecoder.new.call(token)

raise Rack::Firebase::InvalidSubError.new("Invalid subject") if decoded_token["sub"].nil? || decoded_token["sub"] == ""
raise Rack::Firebase::InvalidAuthTimeError.new("Invalid auth time") unless decoded_token["auth_time"] <= Time.now.to_i
raise Rack::Firebase::InvalidSubError.new("Invalid subject") if decoded_token["sub"].nil? || decoded_token["sub"] == ""
raise Rack::Firebase::InvalidAuthTimeError.new("Invalid auth time") unless decoded_token["auth_time"] <= Time.now.to_i

env[USER_UID] = decoded_token["sub"]
@app.call(env)
rescue JWT::JWKError => error # Issues with fetched JWKs
error_responder.call(error, "unauthorized")
rescue JWT::ExpiredSignature => error # Token has expired
error_responder.call(error, "expired")
rescue JWT::InvalidIatError => error # invalid issued at claim (iat)
error_responder.call(error, "unauthorized")
rescue JWT::InvalidIssuerError => error # invalid issuer
error_responder.call(error, "unauthorized")
rescue JWT::InvalidAudError => error # invalid audience
error_responder.call(error, "unauthorized")
rescue JWT::DecodeError => error # General JWT error
error_responder.call(error, "unauthorized")
rescue Rack::Firebase::InvalidSubError => error # subject is empty or missing
error_responder.call(error, "unauthorized")
rescue Rack::Firebase::InvalidAuthTimeError => error # auth time is in the future
error_responder.call(error, "unauthorized")
env[USER_UID] = decoded_token["sub"]
@app.call(env)
rescue JWT::JWKError => error # Issues with fetched JWKs
error_responder.call(error, "unauthorized")
rescue JWT::ExpiredSignature => error # Token has expired
error_responder.call(error, "expired")
rescue JWT::InvalidIatError => error # invalid issued at claim (iat)
error_responder.call(error, "unauthorized")
rescue JWT::InvalidIssuerError => error # invalid issuer
error_responder.call(error, "unauthorized")
rescue JWT::InvalidAudError => error # invalid audience
error_responder.call(error, "unauthorized")
rescue JWT::DecodeError => error # General JWT error
error_responder.call(error, "unauthorized")
rescue Rack::Firebase::InvalidSubError => error # subject is empty or missing
error_responder.call(error, "unauthorized")
rescue Rack::Firebase::InvalidAuthTimeError => error # auth time is in the future
error_responder.call(error, "unauthorized")
end
else
@app.call(env)
end
end

private
Expand Down
24 changes: 24 additions & 0 deletions spec/rack/firebase/middleware_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,24 @@
expect(last_response).to be_ok
expect(last_request.env[described_class::USER_UID]).to eq("123")
end

context "and route is considered public" do
before do
Rack::Firebase.configure do |config|
config.public_routes = ["/"]
end
end

after do
Rack::Firebase.configuration.reset!
end

it "returns a 200 success" do
get "/"

expect(last_response).to be_ok
end
end
end
end

Expand All @@ -296,6 +314,12 @@

let(:net_response) { Net::HTTPResponse.new(1.0, "200", "OK") }

before do
Rack::Firebase.configure do |config|
config.project_ids = ["test-project-id"]
end
end

context "when there are no cached public keys" do
let(:certs) { File.read("#{CERT_PATH}/certificates.json") }
let(:cache_control) { "public, max-age=19302, must-revalidate, no-transform" }
Expand Down
3 changes: 3 additions & 0 deletions spec/rack/firebase_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@
before do
Rack::Firebase.configure do |config|
config.project_ids = 1
config.public_routes = ["/healthcheck"]
end
end

it "resets the configuration" do
expect(Rack::Firebase.configuration.project_ids).to eq(1)
expect(Rack::Firebase.configuration.public_routes).to eq(["/healthcheck"])
Rack::Firebase.configuration.reset!
expect(Rack::Firebase.configuration.project_ids).to eq([])
expect(Rack::Firebase.configuration.public_routes).to eq([])
end
end
end

0 comments on commit 7c4cad3

Please sign in to comment.