real_savvy 0.0.6 → 0.0.7

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
  SHA1:
3
- metadata.gz: b70dbda002738e46c0e953b796145e67fe4f23ea
4
- data.tar.gz: 00b5011fa01800d6be5fbc5263609920370bd005
3
+ metadata.gz: 83c3eb21fb475cd2006eeaeff541e57edba481c6
4
+ data.tar.gz: 3e9c22f823cb9e87dc86677df7d6c33215b95db3
5
5
  SHA512:
6
- metadata.gz: 2c7f6071923ed687d91efa485a07017f3acc6d4fc84563261951d36db3db474ee698f171fb7ec03d6eba7464a79f159e197310aca7dcf591d2762ea9057ec2ae
7
- data.tar.gz: c34eb8226def258055179b077d51b2aad6bbc412157d34dc491f651c2a638604496f56cc647ce2e5c6b883429e226ab886fd6e4aa775e6c1b5a6bb744a49023c
6
+ metadata.gz: 6d417e599280f1bcea965a7da684ae7c1f55952d88592f52098140d02d9c97f4521fa6b76c08b10f737b06057dd51c178dc6298b1cf0661b8ee30f4cbde14b5d
7
+ data.tar.gz: 792908183863481ff23f39fce1707c55ce92d8f16bb3a77f17816105d98ef9abaf5b67af55352761eefe7a65cb4f5a14c4982d1d9975c52f29e498948662c435
@@ -0,0 +1,145 @@
1
+ module RealSavvy
2
+ module JWT
3
+ class AbstractToken
4
+ # In order of access level
5
+ SCOPE_VERBS = %w{public read write admin}.freeze
6
+
7
+ attr_reader :scopes, :user, :site, :token, :header
8
+
9
+ def initialize(token)
10
+ @token = token
11
+ standardized_token
12
+ retrieve_claims
13
+ retrieve_scopes
14
+ retrieve_audience
15
+ retrieve_site
16
+ retrieve_subject
17
+ retrieve_user
18
+ end
19
+
20
+ def self.decode(token)
21
+ new(token)
22
+ end
23
+
24
+ def scope_includes?(*scope_parts)
25
+ !scope_parts.empty? && (
26
+ scope_parts = scope_parts.dup.map(&:to_s)
27
+ verbs_matches = self.class.verbs_matches(scope_parts.pop)
28
+
29
+ (0..scope_parts.length).any? do |depth|
30
+ verbs_matches.any? do |verb|
31
+ (scope_parts[0...depth] + [verb]).inject(scopes) do |m, v|
32
+ m&.[](v)
33
+ end
34
+ end
35
+ end
36
+ )
37
+ end
38
+
39
+ def scope_includes!(*scope_parts)
40
+ scope_includes?(*scope_parts) || fail(::RealSavvy::JWT::Unauthorized)
41
+ end
42
+
43
+ def self.verbs_matches(verb)
44
+ verb_index = SCOPE_VERBS.index(verb)
45
+ verb_index ? SCOPE_VERBS[verb_index..-1] : []
46
+ end
47
+
48
+ def for_site?
49
+ audience_is_site? && subject_is_site?
50
+ end
51
+
52
+ def for_site!
53
+ for_site? || fail(::RealSavvy::JWT::Unauthorized)
54
+ end
55
+
56
+ def for_user?
57
+ audience_is_site? && (subject_is_user? || subject_is_imposter?)
58
+ end
59
+
60
+ def audience_is_site?
61
+ audience.respond_to?(:is_real_savvy_site?) &&
62
+ audience.is_real_savvy_site?
63
+ end
64
+
65
+ def subject_is_user?
66
+ subject.respond_to?(:is_real_savvy_user?) &&
67
+ subject.is_real_savvy_user?
68
+ end
69
+
70
+ def subject_is_imposter?
71
+ subject.respond_to?(:is_real_savvy_imposter?) &&
72
+ subject.is_real_savvy_imposter?
73
+ end
74
+
75
+ def subject_is_site?
76
+ subject.respond_to?(:is_real_savvy_site?) &&
77
+ subject.is_real_savvy_site?
78
+ end
79
+
80
+ def for_user!
81
+ for_user? || fail(::RealSavvy::JWT::Unauthorized)
82
+ end
83
+
84
+ def valid?
85
+ claims && claims.length > 0 && (for_site? || for_user?) && validate_token
86
+ end
87
+
88
+ def validate_token
89
+ raise NotImplementedError, "subclass did not define #validate_token"
90
+ end
91
+
92
+ def imposter?
93
+ @imposter ? true : false
94
+ end
95
+
96
+ def to_share_token
97
+ share_token_json = Hash[claims.slice('aud','sub').map{ |key,value| [key, value.to_s.split('/')[-2,2].join('/')] }].to_json
98
+ Base64.urlsafe_encode64(share_token_json, padding: false)
99
+ end
100
+
101
+ private
102
+
103
+ attr_reader :claims, :audience, :subject
104
+
105
+ def retrieve_claims
106
+ raise NotImplementedError, "subclass did not define #retrieve_claims"
107
+ end
108
+
109
+ def retrieve_audience
110
+ @audience = ::RealSavvy::JWT::Config.retrieve_audience(claims) if claims
111
+ end
112
+
113
+ def retrieve_subject
114
+ @subject = ::RealSavvy::JWT::Config.retrieve_subject(claims) if claims
115
+ end
116
+
117
+ def retrieve_site
118
+ @site = audience
119
+ end
120
+
121
+ def retrieve_user
122
+ if subject_is_user?
123
+ @user = subject
124
+ elsif subject_is_imposter?
125
+ @user = subject.user
126
+ @imposter = true
127
+ end
128
+ end
129
+
130
+ def raw_scopes
131
+ claims&.fetch('scopes', nil).to_a
132
+ end
133
+
134
+ def retrieve_scopes
135
+ @scopes = raw_scopes.each_with_object({}) do |scope, result|
136
+ scope.split(':').inject(result) { |m, v| m[v] ||= {} }
137
+ end
138
+ end
139
+
140
+ def standardized_token
141
+ # If token needs to be cleaned up do it here in subclasses
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,54 @@
1
+ module RealSavvy
2
+ module JWT
3
+ module Config
4
+ def self.public_key
5
+ if block_given?
6
+ @public_key = Proc.new
7
+ else
8
+ result = @public_key.is_a?(Proc) ? @public_key.call : @public_key
9
+ result.is_a?(OpenSSL::PKey::RSA) ? result : OpenSSL::PKey::RSA.new(result)
10
+ end
11
+ end
12
+
13
+ def self.public_key= value
14
+ @public_key = value
15
+ end
16
+
17
+ def self.retrieve_audience claims = nil
18
+ if block_given?
19
+ @retrieve_audience = Proc.new
20
+ else
21
+ @retrieve_audience.call(claims)
22
+ end
23
+ end
24
+
25
+ def self.retrieve_audience= value
26
+ @retrieve_audience = value
27
+ end
28
+
29
+ def self.retrieve_subject claims = nil
30
+ if block_given?
31
+ @retrieve_subject = Proc.new
32
+ else
33
+ @retrieve_subject.call(claims)
34
+ end
35
+ end
36
+
37
+ def self.retrieve_subject= value
38
+ @retrieve_subject = value
39
+ end
40
+
41
+ def self.validate_token token = nil
42
+ if block_given?
43
+ @validate_token = Proc.new
44
+ else
45
+ @validate_token.call(token)
46
+ end
47
+ end
48
+
49
+ def self.validate_token= value
50
+ @validate_token = value
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,32 @@
1
+ module RealSavvy
2
+ module JWT
3
+ class ShareToken < AbstractToken
4
+
5
+ def short_token
6
+ @token.split('.')[1]
7
+ end
8
+
9
+ private
10
+
11
+ def retrieve_claims
12
+ @claims, @header = ::JWT.decode(
13
+ token,
14
+ nil,
15
+ false,
16
+ )
17
+ rescue ::JWT::DecodeError => e
18
+ raise ::RealSavvy::JWT::BadCredentials.new(e.message)
19
+ end
20
+
21
+ def validate_token
22
+ true
23
+ end
24
+
25
+ def standardized_token
26
+ token_parts = @token.split('.')
27
+ header = Base64.urlsafe_encode64({typ:"JWT",alg:"none"}.to_json, padding: false)
28
+ @token = [header, (token_parts.length == 1 ? token_parts[0] : token_parts[1]), nil].join('.')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,186 +1,32 @@
1
1
  module RealSavvy
2
2
  module JWT
3
- class Token
4
- # In order of access level
5
- SCOPE_VERBS = %w{public read write admin}.freeze
6
-
7
- attr_reader :scopes, :user, :site, :token
8
-
9
- def initialize(token)
10
- @token = token
11
- retrieve_claims
12
- retrieve_scopes
13
- retrieve_audience
14
- retrieve_site
15
- retrieve_subject
16
- retrieve_user
17
- end
18
-
19
- def self.public_key
20
- if block_given?
21
- @public_key = Proc.new
22
- else
23
- result = @public_key.is_a?(Proc) ? @public_key.call : @public_key
24
- result.is_a?(OpenSSL::PKey::RSA) ? result : OpenSSL::PKey::RSA.new(result)
25
- end
26
- end
27
-
28
- def self.public_key= value
29
- @public_key = value
30
- end
31
-
32
- def self.retrieve_audience claims = nil
33
- if block_given?
34
- @retrieve_audience = Proc.new
35
- else
36
- @retrieve_audience.call(claims)
37
- end
38
- end
39
-
40
- def self.retrieve_audience= value
41
- @retrieve_audience = value
42
- end
43
-
44
- def self.retrieve_subject claims = nil
45
- if block_given?
46
- @retrieve_subject = Proc.new
47
- else
48
- @retrieve_subject.call(claims)
49
- end
50
- end
51
-
52
- def self.retrieve_subject= value
53
- @retrieve_subject = value
54
- end
55
-
56
- def self.validate_token token = nil
57
- if block_given?
58
- @validate_token = Proc.new
59
- else
60
- @validate_token.call(token)
61
- end
62
- end
63
-
64
- def self.validate_token= value
65
- @validate_token = value
66
- end
67
-
68
- def self.decode(token)
69
- new(token)
70
- end
71
-
72
- def scope_includes?(*scope_parts)
73
- !scope_parts.empty? && (
74
- scope_parts = scope_parts.dup.map(&:to_s)
75
- verbs_matches = self.class.verbs_matches(scope_parts.pop)
76
-
77
- (0..scope_parts.length).any? do |depth|
78
- verbs_matches.any? do |verb|
79
- (scope_parts[0...depth] + [verb]).inject(scopes) do |m, v|
80
- m&.[](v)
81
- end
82
- end
83
- end
3
+ class Token < AbstractToken
4
+
5
+ def to_share_token
6
+ share_token_payload_keys = ['aud','sub']
7
+ share_token_payload = ::Hash[[share_token_payload_keys, claims.values_at(*share_token_payload_keys)].transpose]
8
+ ShareToken.new(
9
+ ::JWT.encode(
10
+ share_token_payload, nil, 'none'
11
+ )
84
12
  )
85
13
  end
86
14
 
87
- def scope_includes!(*scope_parts)
88
- scope_includes?(*scope_parts) || fail(::RealSavvy::JWT::Unauthorized)
89
- end
90
-
91
- def self.verbs_matches(verb)
92
- verb_index = SCOPE_VERBS.index(verb)
93
- verb_index ? SCOPE_VERBS[verb_index..-1] : []
94
- end
95
-
96
- def for_site?
97
- audience_is_site? && subject_is_site?
98
- end
99
-
100
- def for_site!
101
- for_site? || fail(::RealSavvy::JWT::Unauthorized)
102
- end
103
-
104
- def for_user?
105
- audience_is_site? && (subject_is_user? || subject_is_imposter?)
106
- end
107
-
108
- def audience_is_site?
109
- audience.respond_to?(:is_real_savvy_site?) &&
110
- audience.is_real_savvy_site?
111
- end
112
-
113
- def subject_is_user?
114
- subject.respond_to?(:is_real_savvy_user?) &&
115
- subject.is_real_savvy_user?
116
- end
117
-
118
- def subject_is_imposter?
119
- subject.respond_to?(:is_real_savvy_imposter?) &&
120
- subject.is_real_savvy_imposter?
121
- end
122
-
123
- def subject_is_site?
124
- subject.respond_to?(:is_real_savvy_site?) &&
125
- subject.is_real_savvy_site?
126
- end
127
-
128
- def for_user!
129
- for_user? || fail(::RealSavvy::JWT::Unauthorized)
130
- end
131
-
132
- def valid?
133
- claims && claims.length > 0 && (for_site? || for_user?) && self.class.validate_token(token)
134
- end
135
-
136
- def imposter?
137
- @imposter ? true : false
138
- end
139
-
140
15
  private
141
16
 
142
- attr_reader :claims, :audience, :subject
143
-
144
17
  def retrieve_claims
145
- @claims = ::JWT.decode(
146
- token,
147
- self.class.public_key,
148
- true,
149
- algorithm: 'RS256',
150
- ).first
18
+ @claims, @header = ::JWT.decode(
19
+ token,
20
+ ::RealSavvy::JWT::Config.public_key,
21
+ true,
22
+ algorithm: 'RS256',
23
+ )
151
24
  rescue ::JWT::DecodeError => e
152
25
  raise ::RealSavvy::JWT::BadCredentials.new(e.message)
153
26
  end
154
27
 
155
- def retrieve_audience
156
- @audience = self.class.retrieve_audience(claims) if claims
157
- end
158
-
159
- def retrieve_subject
160
- @subject = self.class.retrieve_subject(claims) if claims
161
- end
162
-
163
- def retrieve_site
164
- @site = audience
165
- end
166
-
167
- def retrieve_user
168
- if subject_is_user?
169
- @user = subject
170
- elsif subject_is_imposter?
171
- @user = subject.user
172
- @imposter = true
173
- end
174
- end
175
-
176
- def raw_scopes
177
- claims&.fetch('scopes', nil).to_a
178
- end
179
-
180
- def retrieve_scopes
181
- @scopes = raw_scopes.each_with_object({}) do |scope, result|
182
- scope.split(':').inject(result) { |m, v| m[v] ||= {} }
183
- end
28
+ def validate_token
29
+ ::RealSavvy::JWT::Config.validate_token(token)
184
30
  end
185
31
  end
186
32
  end
@@ -4,5 +4,7 @@ module RealSavvy::JWT
4
4
 
5
5
  end
6
6
 
7
+ require 'real_savvy/jwt/abstract_token'
7
8
  require 'real_savvy/jwt/token'
9
+ require 'real_savvy/jwt/share_token'
8
10
  Dir[File.dirname(__FILE__) + '/jwt/*.rb'].each {|file| require file }
@@ -1,3 +1,3 @@
1
1
  module RealSavvy
2
- VERSION = [0,0,6]
2
+ VERSION = [0,0,7]
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: real_savvy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Rauh
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2018-03-15 00:00:00.000000000 Z
13
+ date: 2018-03-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: faraday
@@ -166,8 +166,11 @@ files:
166
166
  - lib/real_savvy/connection.rb
167
167
  - lib/real_savvy/document.rb
168
168
  - lib/real_savvy/jwt.rb
169
+ - lib/real_savvy/jwt/abstract_token.rb
169
170
  - lib/real_savvy/jwt/bad_credentials.rb
171
+ - lib/real_savvy/jwt/config.rb
170
172
  - lib/real_savvy/jwt/imposter.rb
173
+ - lib/real_savvy/jwt/share_token.rb
171
174
  - lib/real_savvy/jwt/site.rb
172
175
  - lib/real_savvy/jwt/token.rb
173
176
  - lib/real_savvy/jwt/unauthorized.rb