Skip to content

Commit

Permalink
CI added and Rubocop fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
sardaukar committed Sep 30, 2024
1 parent 455479c commit 6f24f64
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 39 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['3.0', '3.1', '3.2', '3.3', ruby-head]

steps:
- uses: actions/checkout@v4
- name: Set up Ruby ${{ matrix.ruby-version }}
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby-version }}
bundler-cache: true # 'bundle install' and cache
- name: Run specs
run: |
bundle exec rspec
17 changes: 17 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Lint

on: [push, pull_request]

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Ruby ${{ matrix.ruby-version }}
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
bundler-cache: true # 'bundle install' and cache
- name: Run specs
run: |
bundle exec rubocop
16 changes: 10 additions & 6 deletions lib/warden/jwt_auth.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ module Warden
module JWTAuth
extend Dry::Configurable

@@jwks = nil
@jwks = nil

def symbolize_keys(hash)
hash.transform_keys(&:to_sym)
Expand All @@ -39,14 +39,18 @@ def constantize_values(hash)
end

def init_jkws_loader(url)
if url
@@jwks = JWKS.new(url)
JWTAuth.config.algorithm = @@jwks.algo
end
return unless url

@jwks = JWKS.new(url)
JWTAuth.config.algorithm = @jwks.algo
end

def self.jwks
@@jwks
@jwks
end

def jwks
self.class.jwks
end

module_function :init_jkws_loader, :constantize_values, :symbolize_keys, :upcase_first_items
Expand Down
2 changes: 1 addition & 1 deletion lib/warden/jwt_auth/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class NilUser < JWT::DecodeError
class WrongScope < JWT::DecodeError
end

# Error raised when trying to decode a token without scope claim and
# Error raised when trying to decode a token without scope claim and
# no default_scope set
class MissingScopeWithNoDefaultFallback < JWT::DecodeError
end
Expand Down
18 changes: 10 additions & 8 deletions lib/warden/jwt_auth/jwks.rb
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
# frozen_string_literal: true

module Warden
module JWTAuth
# JWKS fetcher class.
#
# Uses a Rails cache key to store the payload
class JWKS

JWKS_CACHE_KEY = "auth/jwks-json".freeze
JWKS_CACHE_KEY = 'auth/jwks-json'

def initialize(url)
@jwks_url = url
end

def loader(options={})
def loader(options = {})
jwks(force: options[:invalidate]) || {}
end

def algo(key_index=0)
def algo(key_index = 0)
loader[:keys][key_index][:alg]
end

private

def fetch_jwks
response = Faraday.get(@jwks_url)
if response.status == 200
JSON.parse(response.body.to_s)
end
JSON.parse(response.body.to_s) if response.status == 200
end

def jwks(force: false)
Expand All @@ -32,4 +34,4 @@ def jwks(force: false)
end
end
end
end
end
7 changes: 4 additions & 3 deletions lib/warden/jwt_auth/strategy.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'warden'
require 'semantic_logger'

module Warden
module JWTAuth
Expand All @@ -21,13 +22,13 @@ def authenticate!
aud = EnvHelper.aud_header(env)
user = UserDecoder.new.call(token, scope, aud)

logger.warn("JWT accepted", user: user.id) if user
logger.warn('JWT accepted', user: user.id) if user

success!(user)
rescue JWT::DecodeError => e
logger.error("JWT decoding failed", message: e.message)
logger.error('JWT decoding failed', message: e.message)

fail!(e.message)
fail!(e.message)
end

private
Expand Down
13 changes: 2 additions & 11 deletions lib/warden/jwt_auth/token_decoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,9 @@ def call(token)
def decode(token, secret)
if JWTAuth.config.jwks_url
jwks = Warden::JWTAuth.jwks
JWT.decode(token,
secret,
true,
algorithm: jwks.algo,
verify_jti: true,
jwks: jwks.loader)[0]
JWT.decode(token, secret, true, algorithm: jwks.algo, verify_jti: true, jwks: jwks.loader)[0]
else
JWT.decode(token,
secret,
true,
algorithm: algorithm,
verify_jti: true)[0]
JWT.decode(token, secret, true, algorithm: algorithm, verify_jti: true)[0]
end
end
end
Expand Down
25 changes: 20 additions & 5 deletions lib/warden/jwt_auth/user_decoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ def initialize(**args)
# encoded user
# @raise [Errors::NilUser] when decoded user is nil
# @raise [Errors::WrongScope] when encoded scope does not match with scope
# @raise [Errors::WrongAud] when encoded aud does not match with aud
# argument
# @raise [Errors::WrongAud] when encoded aud does not match with aud argument
# rubocop:disable Metrics/MethodLength
def call(token, scope, aud)
config = JWTAuth.config
payload = TokenDecoder.new.call(token)

if payload_has_no_scope?(payload)
raise Errors::MissingScopeWithNoDefaultFallback, 'payload has no scp claim and no default_scope is set' unless config.default_scope
unless config.default_scope
raise Errors::MissingScopeWithNoDefaultFallback, 'payload has no scp claim and no default_scope is set'
end

scope = payload['scp'] = config.default_scope
end

Expand All @@ -43,22 +46,34 @@ def call(token, scope, aud)
check_valid_user(payload, user, scope)
user
end
# rubocop:enable Metrics/MethodLength

private

def check_valid_claims(payload, scope, aud)
raise Errors::WrongScope, 'wrong scope' unless helper.scope_matches?(payload, scope)

if aud.nil? && !payload['aud'].nil?
raise Errors::MissingAudHeaderWithNoFallback, 'aud_header is missing and valid_auds setting is unset' unless JWTAuth.config.valid_auds
raise Errors::WrongAud, 'aud_header missing and aud claim is not part of the valid_auds setting' unless helper.aud_matches_valid_ones?(payload)
check_empty_aud_header(payload)
else
raise Errors::WrongAud, 'wrong aud' unless helper.aud_matches?(payload, aud)
end

scope
end

def check_empty_aud_header(payload)
unless JWTAuth.config.valid_auds
raise Errors::MissingAudHeaderWithNoFallback, 'aud_header is missing and valid_auds setting is unset'
end

# rubocop:disable Style/GuardClause
unless helper.aud_matches_valid_ones?(payload)
raise Errors::WrongAud, 'aud_header missing and aud claim is not part of the valid_auds setting'
end
# rubocop:enable Style/GuardClause
end

def check_valid_user(payload, user, scope)
raise Errors::NilUser, 'nil user' unless user

Expand Down
4 changes: 4 additions & 0 deletions spec/support/fixtures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ module Fixtures
class User
include Singleton

def id
1
end

def jwt_subject
'1'
end
Expand Down
12 changes: 7 additions & 5 deletions spec/warden/jwt_auth/strategy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@
end
end

context "when issuer is configured" do
let(:token) { Warden::JWTAuth::TokenEncoder.new.call({issuer: issuer}) }
# rubocop:disable RSpec/NestedGroups
context 'when issuer is configured' do
let(:token) { Warden::JWTAuth::TokenEncoder.new.call({ issuer: issuer }) }
let(:env) { { 'HTTP_AUTHORIZATION' => "Bearer #{token}" } }
let(:issuer) { 'http://example.com' }
let(:strategy) { described_class.new(env, :user) }
Expand All @@ -43,20 +44,21 @@
end
end

context "when the issuer claim matches the configured issuer" do
context 'when the issuer claim matches the configured issuer' do
it 'returns true' do
expect(strategy).to be_valid
end
end

context "when the issuer claim does not match the configured issuer" do
let(:token) { Warden::JWTAuth::TokenEncoder.new.call({"iss" => 'http://example.org'}) }
context 'when the issuer claim does not match the configured issuer' do
let(:token) { Warden::JWTAuth::TokenEncoder.new.call({ 'iss' => 'http://example.org' }) }

it 'returns false' do
expect(strategy).not_to be_valid
end
end
end
# rubocop:enable RSpec/NestedGroups
end

describe '#persist?' do
Expand Down
1 change: 1 addition & 0 deletions spec/warden/jwt_auth/token_encoder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@

context 'with issuer claim' do
let(:issuer) { 'http://example.com' }

before do
Warden::JWTAuth.configure do |config|
config.issuer = issuer
Expand Down

0 comments on commit 6f24f64

Please sign in to comment.