zaikio-jwt_auth 0.2.4 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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