zaikio-jwt_auth 0.2.4 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16afec7be22352a9cc13e7bc0e65edfcbd1aef93073e3cb4f8f3059eda576859
4
- data.tar.gz: f1608ab958c199ff881416298bc17ffd02c3aea3f41315789009af817542f7c3
3
+ metadata.gz: fd2758c610957007baf7499e46f22d286a5c61dceb5895270080f20af8e5a57d
4
+ data.tar.gz: 5c945887dca4cd07ebfc836a5cbadb81667a56dbed0c6f67152dba297d4399fd
5
5
  SHA512:
6
- metadata.gz: 52e9deeaed67d548070b6e28317e000232831896dcef98dabd1e333f2e05e4a6166618ff7cf176e88ff0a6cdb148d2291604366f3f7155149a904a821128bfe1
7
- data.tar.gz: 570301e458fbba82a6ace338dcbc4be1f481d2e20d53a0d28b40f096bf56baf154408ce7ae4cb5b18d691f071580de64b012d3daabf5a81f4b8a87db95186039
6
+ metadata.gz: 73a3192d97b3f20caab44a96306258cd7b1b0240fb9e912726e3dfd536ef46183e0590a9cb513ed4be6afb66f4ee3c0a415153c4a7e7259a7bd569374e30eab4
7
+ data.tar.gz: bb9db302ba5caafeae825b25c244a91d213c1026d879c62ca2da230db6f29ade726121fcd0c0727c1e5625a84e2ed2cfb282a25ecaa827562efe6e6a9cb1a58f
data/README.md CHANGED
@@ -49,7 +49,7 @@ end
49
49
 
50
50
  ### 4. Update Revoked Access Tokens by Webhook
51
51
 
52
- This gem automatically registers a webhook, if you have properly setup [Zaikio::Webhooks](https://github.com/crispymtn/zaikio-webhooks).
52
+ This gem automatically registers a webhook, if you have properly setup [Zaikio::Webhooks](https://github.com/zaikio/zaikio-webhooks).
53
53
 
54
54
 
55
55
  ### 5. Add more restrictions to your resources:
@@ -118,3 +118,32 @@ class API::ResourcesController < API::ApplicationController
118
118
  authorize_by_jwt_scopes 'resources', unless: -> { params[:skip] == '1' }
119
119
  end
120
120
  ```
121
+
122
+ ### Usage outside a Rails controller
123
+
124
+ If you need to access a JWT outside the normal Rails controllers (e.g. in a Rack
125
+ middleware), there's a static helper method `.extract` which you can use:
126
+
127
+ ```ruby
128
+ class MyRackMiddleware < Rack::Middleware
129
+ def call(env)
130
+ token = Zaikio::JWTAuth.extract(env["HTTP_AUTHORIZATION"])
131
+ puts token.subject_type #=> "Organization"
132
+ ...
133
+ ```
134
+
135
+ This function expects to receive the string in the format `"Bearer $token"`.
136
+
137
+ ## Contributing
138
+
139
+ **Make sure you have the dummy app running locally to validate your changes.**
140
+
141
+ - Make your changes and submit a pull request for them
142
+ - Make sure to update `CHANGELOG.md`
143
+
144
+ To release a new version of the gem:
145
+ - Update the version in `lib/zaikio/jwt_auth/version.rb`
146
+ - Update `CHANGELOG.md` to include the new version and its release date
147
+ - Commit and push your changes
148
+ - Create a [new release on GitHub](https://github.com/zaikio/zaikio-jwt_auth/releases/new)
149
+ - CircleCI will build the Gem package and push it Rubygems for you
@@ -2,8 +2,8 @@ module Zaikio
2
2
  module JWTAuth
3
3
  class RevokeAccessTokenJob < ApplicationJob
4
4
  def perform(event)
5
- DirectoryCache.update("api/v1/blacklisted_access_tokens.json", expires_after: 60.minutes) do |data|
6
- data["blacklisted_token_ids"] << event.payload["access_token_id"]
5
+ DirectoryCache.update("api/v1/revoked_access_tokens.json", expires_after: 60.minutes) do |data|
6
+ data["revoked_token_ids"] << event.payload["access_token_id"]
7
7
  data
8
8
  end
9
9
  end
@@ -1,5 +1,6 @@
1
1
  require "jwt"
2
2
  require "oj"
3
+ require "active_support/core_ext/integer/time"
3
4
  require "zaikio/jwt_auth/railtie"
4
5
  require "zaikio/jwt_auth/configuration"
5
6
  require "zaikio/jwt_auth/directory_cache"
@@ -26,15 +27,16 @@ module Zaikio
26
27
  end
27
28
 
28
29
  def self.revoked_jwt?(jti)
29
- blacklisted_token_ids.include?(jti)
30
+ revoked_token_ids.include?(jti)
30
31
  end
31
32
 
32
- def self.blacklisted_token_ids
33
+ def self.revoked_token_ids
33
34
  return [] if mocked_jwt_payload
34
35
 
35
- return configuration.blacklisted_token_ids if configuration.blacklisted_token_ids
36
-
37
- DirectoryCache.fetch("api/v1/blacklisted_access_tokens.json", expires_after: 60.minutes)["blacklisted_token_ids"]
36
+ configuration.revoked_token_ids || DirectoryCache.fetch(
37
+ "api/v1/revoked_access_tokens.json",
38
+ expires_after: 60.minutes
39
+ )["revoked_token_ids"]
38
40
  end
39
41
 
40
42
  def self.included(base)
@@ -50,6 +52,20 @@ module Zaikio
50
52
  @mocked_jwt_payload = payload
51
53
  end
52
54
 
55
+ HEADER_FORMAT = /\ABearer (.+)\z/.freeze
56
+
57
+ def self.extract(authorization_header_string)
58
+ return TokenData.new(Zaikio::JWTAuth.mocked_jwt_payload) if Zaikio::JWTAuth.mocked_jwt_payload
59
+
60
+ return if authorization_header_string.blank?
61
+
62
+ return unless (token = authorization_header_string[HEADER_FORMAT, 1])
63
+
64
+ payload, = JWT.decode(token, nil, true, algorithms: ["RS256"], jwks: JWK.loader)
65
+
66
+ TokenData.new(payload)
67
+ end
68
+
53
69
  module ClassMethods
54
70
  def authorize_by_jwt_subject_type(type = nil)
55
71
  @authorize_by_jwt_subject_type ||= type
@@ -66,11 +82,10 @@ module Zaikio
66
82
 
67
83
  module InstanceMethods
68
84
  def authenticate_by_jwt
69
- render_error("no_jwt_passed", status: :unauthorized) && return unless jwt_from_auth_header
85
+ token_data = Zaikio::JWTAuth.extract(request.headers["Authorization"])
86
+ return render_error("no_jwt_passed", status: :unauthorized) unless token_data
70
87
 
71
- token_data = TokenData.new(jwt_payload)
72
-
73
- return if show_error_if_token_is_blacklisted(token_data)
88
+ return if show_error_if_token_is_revoked(token_data)
74
89
 
75
90
  return if show_error_if_authorize_by_jwt_subject_type_fails(token_data)
76
91
 
@@ -83,11 +98,11 @@ module Zaikio
83
98
  render_error("invalid_jwt") && (return)
84
99
  end
85
100
 
86
- def update_blacklisted_access_tokens_by_webhook
101
+ def update_revoked_access_tokens_by_webhook
87
102
  return unless params[:name] == "directory.revoked_access_token"
88
103
 
89
- DirectoryCache.update("api/v1/blacklisted_access_tokens.json", expires_after: 60.minutes) do |data|
90
- data["blacklisted_token_ids"] << params[:payload][:access_token_id]
104
+ DirectoryCache.update("api/v1/revoked_access_tokens.json", expires_after: 60.minutes) do |data|
105
+ data["revoked_token_ids"] << params[:payload][:access_token_id]
91
106
  data
92
107
  end
93
108
 
@@ -96,21 +111,6 @@ module Zaikio
96
111
 
97
112
  private
98
113
 
99
- def jwt_from_auth_header
100
- return true if Zaikio::JWTAuth.mocked_jwt_payload
101
-
102
- auth_header = request.headers["Authorization"]
103
- auth_header.split("Bearer ").last if /Bearer/.match?(auth_header)
104
- end
105
-
106
- def jwt_payload
107
- return Zaikio::JWTAuth.mocked_jwt_payload if Zaikio::JWTAuth.mocked_jwt_payload
108
-
109
- payload, = JWT.decode(jwt_from_auth_header, nil, true, algorithms: ["RS256"], jwks: JWK.loader)
110
-
111
- payload
112
- end
113
-
114
114
  def show_error_if_authorize_by_jwt_scopes_fails(token_data)
115
115
  return if token_data.scope_by_configurations?(
116
116
  self.class.authorize_by_jwt_scopes,
@@ -130,7 +130,7 @@ module Zaikio
130
130
  render_error("unpermitted_subject")
131
131
  end
132
132
 
133
- def show_error_if_token_is_blacklisted(token_data)
133
+ def show_error_if_token_is_revoked(token_data)
134
134
  return unless Zaikio::JWTAuth.revoked_jwt?(token_data.jti)
135
135
 
136
136
  render_error("invalid_jwt")
@@ -4,25 +4,25 @@ module Zaikio
4
4
  module JWTAuth
5
5
  class Configuration
6
6
  HOSTS = {
7
- development: "http://directory.zaikio.test",
8
- test: "http://directory.zaikio.test",
9
- staging: "https://directory.staging.zaikio.com",
10
- sandbox: "https://directory.sandbox.zaikio.com",
11
- production: "https://directory.zaikio.com"
7
+ development: "http://hub.zaikio.test",
8
+ test: "http://hub.zaikio.test",
9
+ staging: "https://hub.staging.zaikio.com",
10
+ sandbox: "https://hub.sandbox.zaikio.com",
11
+ production: "https://hub.zaikio.com"
12
12
  }.freeze
13
13
 
14
- attr_accessor :app_name
15
- attr_accessor :redis, :host
14
+ attr_accessor :app_name, :redis, :host
16
15
  attr_reader :environment
17
- attr_writer :logger, :blacklisted_token_ids, :keys
16
+ attr_writer :logger, :revoked_token_ids, :keys
18
17
 
19
18
  def initialize
20
19
  @environment = :sandbox
21
- @blacklisted_token_ids = nil
20
+ @revoked_token_ids = nil
21
+ @keys = nil
22
22
  end
23
23
 
24
24
  def logger
25
- @logger ||= Logger.new(STDOUT)
25
+ @logger ||= Logger.new($stdout)
26
26
  end
27
27
 
28
28
  def environment=(env)
@@ -31,11 +31,11 @@ module Zaikio
31
31
  end
32
32
 
33
33
  def keys
34
- defined?(@keys) && @keys.is_a?(Proc) ? @keys.call : @keys
34
+ @keys.is_a?(Proc) ? @keys.call : @keys
35
35
  end
36
36
 
37
- def blacklisted_token_ids
38
- @blacklisted_token_ids.is_a?(Proc) ? @blacklisted_token_ids.call : @blacklisted_token_ids
37
+ def revoked_token_ids
38
+ @revoked_token_ids.is_a?(Proc) ? @revoked_token_ids.call : @revoked_token_ids
39
39
  end
40
40
 
41
41
  private
@@ -14,7 +14,7 @@ module Zaikio
14
14
  jti: "unique-access-token-id",
15
15
  nbf: Time.now.to_i,
16
16
  exp: 1.hour.from_now.to_i,
17
- jku: "http://directory.zaikio.test/api/v1/jwt_public_keys.json",
17
+ jku: "http://hub.zaikio.test/api/v1/jwt_public_keys.json",
18
18
  scope: []
19
19
  }.merge(extra_payload).stringify_keys
20
20
  end
@@ -2,7 +2,7 @@ module Zaikio
2
2
  module JWTAuth
3
3
  class TokenData
4
4
  def self.subject_format
5
- %r{^((\w+)/((\w|-)+)\>)?(\w+)/((\w|-)+)$}
5
+ %r{^((\w+)/((\w|-)+)>)?(\w+)/((\w|-)+)$}
6
6
  end
7
7
 
8
8
  def self.actions_by_permission
@@ -33,6 +33,10 @@ module Zaikio
33
33
  @payload["jti"]
34
34
  end
35
35
 
36
+ def expires_at
37
+ Time.zone.at(@payload["exp"]).to_datetime
38
+ end
39
+
36
40
  # scope_options is an array of objects with:
37
41
  # scope, app_name (optional), except/only (array, optional)
38
42
  def scope_by_configurations?(scope_configurations, action_name, context)
@@ -1,5 +1,5 @@
1
1
  module Zaikio
2
2
  module JWTAuth
3
- VERSION = "0.2.4".freeze
3
+ VERSION = "0.4.1".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zaikio-jwt_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - crispymtn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-05-04 00:00:00.000000000 Z
13
+ date: 2021-02-15 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: oj
@@ -78,10 +78,12 @@ files:
78
78
  - lib/zaikio/jwt_auth/test_helper.rb
79
79
  - lib/zaikio/jwt_auth/token_data.rb
80
80
  - lib/zaikio/jwt_auth/version.rb
81
- homepage: https://www.zaikio.com/
81
+ homepage: https://github.com/zaikio/zaikio-jwt_auth
82
82
  licenses:
83
83
  - MIT
84
- metadata: {}
84
+ metadata:
85
+ changelog_uri: https://github.com/zaikio/zaikio-jwt_auth/blob/main/CHANGELOG.md
86
+ source_code_uri: https://github.com/zaikio/zaikio-jwt_auth
85
87
  post_install_message:
86
88
  rdoc_options: []
87
89
  require_paths:
@@ -90,14 +92,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
92
  requirements:
91
93
  - - ">="
92
94
  - !ruby/object:Gem::Version
93
- version: '0'
95
+ version: 2.6.5
94
96
  required_rubygems_version: !ruby/object:Gem::Requirement
95
97
  requirements:
96
98
  - - ">="
97
99
  - !ruby/object:Gem::Version
98
100
  version: '0'
99
101
  requirements: []
100
- rubygems_version: 3.0.3
102
+ rubygems_version: 3.1.4
101
103
  signing_key:
102
104
  specification_version: 4
103
105
  summary: JWT-Based authentication and authorization with zaikio