authentic-jwt 0.0.4 → 0.0.5

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: 59f788359a77abb136b7c38fdcab253d45c00f13
4
- data.tar.gz: 5d21ada90226e6763e18f4e360e5f1eed29ad991
3
+ metadata.gz: 3e6fcda5fe67f9a0e8a4e2831f3d4415ddf32cc9
4
+ data.tar.gz: 15d4b595ceec5f589edbdfc83dddecf3e7f3db09
5
5
  SHA512:
6
- metadata.gz: fb34b5b23fe8000435777be76f5e25d09293523c88658361e6fca0b21c5dbb1d807b2281429d72302ccef32f67cfcf14e810c0bd4d1f4a8415a8ef343fba74fd
7
- data.tar.gz: aea12556a8dac589d6e52ad51cbca4bdd30c488975415cf8fe6a1351159992e06e552f25985e53de72f8dfdacf8d1696366f99a2ef33d2413b1eb578489d8fbd
6
+ metadata.gz: ce798a44e216d19e62d4f4bdf76b447255d7ee4b72c97e1cb6241a384cf9b525f70b79b673930828d25e70634001ebb7e6c378b35e4784aaa5dfdc81113872c5
7
+ data.tar.gz: fda56a15d6d0eca70705f4b958010eaad4b5d35dc603e64f55b7f2f3b357f9eeb88622516e2ac7ef651364bb0ae78e4bbae8523beb6c77708b9b524c0f52abf8
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
-
5
- gem "google-protobuf", "3.2.0.rc2"
data/lib/authentic-jwt.rb CHANGED
@@ -2,3 +2,5 @@ require "authentic_jwt/version"
2
2
  require "authentic_jwt/errors"
3
3
  require "authentic_jwt/payload_pb"
4
4
  require "authentic_jwt/role"
5
+ require "authentic_jwt/validator"
6
+ require "authentic_jwt/authorizer"
@@ -0,0 +1,46 @@
1
+ module AuthenticJwt
2
+ class Authorizer
3
+ def initialize(account_id: ENV["AUTHENTIC_AUTH_ACCOUNT_ID"])
4
+ unless account_id.to_s.empty?
5
+ @account_id = account_id.to_s
6
+ end
7
+ end
8
+
9
+ attr_reader :account_id
10
+
11
+ def call(payload:, scope: nil)
12
+ return unless account_id
13
+
14
+ account = payload.accounts.detect { |account| account.aud == account_id }
15
+
16
+ unless account
17
+ raise Forbidden, "No access to account"
18
+ end
19
+
20
+ roles = account.roles.collect(&:downcase)
21
+
22
+ unless roles.any?
23
+ raise Forbidden, "Account has no roles"
24
+ end
25
+
26
+ acceptable_roles = calculate_acceptable_roles(scope: scope)
27
+
28
+ unless (acceptable_roles & roles).any?
29
+ raise Forbidden, "Account role is too low"
30
+ end
31
+
32
+ true
33
+ end
34
+
35
+ protected
36
+
37
+ def calculate_acceptable_roles(scope:)
38
+ return [] unless scope
39
+ case scope
40
+ when "read" then AuthenticJwt::Role.read
41
+ when "write" then AuthenticJwt::Role.write
42
+ else raise ArgumentError
43
+ end
44
+ end
45
+ end
46
+ end
@@ -5,7 +5,7 @@ module AuthenticJwt
5
5
 
6
6
  def jwt_sub
7
7
  return unless jwt_payload
8
- jwt_payload["sub"]
8
+ jwt_payload.sub
9
9
  end
10
10
  end
11
11
  end
@@ -1,7 +1,5 @@
1
1
  require "authentic_jwt/grape/extension"
2
2
  require "authentic_jwt/grape/auth_methods"
3
- require "openssl"
4
- require "jwt"
5
3
 
6
4
  module AuthenticJwt
7
5
  module Grape
@@ -9,39 +7,26 @@ module AuthenticJwt
9
7
  def before
10
8
  return unless scope
11
9
 
12
- raise Unauthorized, "JWT public key not present" unless public_key
10
+ validator = AuthenticJwt::Validator.new
11
+ payload = validator.call(header: header)
13
12
 
14
- raise Unauthorized, "Authorization header not present" unless authorization_header
15
-
16
- raise Unauthorized, "Bearer token not present" unless bearer_token
17
-
18
- raise Unauthorized, "JWT payload not present" unless jwt_payload
13
+ authorizer = AuthenticJwt::Authorizer.new
14
+ authorizer.call(payload: payload, scope: scope)
19
15
 
20
16
  context.extend(AuthMethods)
21
- context.jwt_payload = jwt_payload
22
-
23
- return unless account_id
24
-
25
- raise Forbidden, "Account has no role" unless account_roles.any?
26
-
27
- raise Forbidden, "Account role is too low" unless (acceptable_roles & account_roles).any?
17
+ context.jwt_payload = payload
28
18
  end
29
19
 
30
20
  protected
31
21
 
32
- PUBLIC_KEY_ENV_VAR = "AUTHENTIC_AUTH_PUBLIC_KEY".freeze
33
- ACCOUNT_ID_ENV_VAR = "AUTHENTIC_AUTH_ACCOUNT_ID".freeze
34
- BEARER_PATTERN = /Bearer (.+)/
22
+ def header
23
+ env["HTTP_AUTHORIZATION"]
24
+ end
35
25
 
36
26
  def context
37
27
  env["api.endpoint"]
38
28
  end
39
29
 
40
- def authorization_header
41
- return if env["HTTP_AUTHORIZATION"].to_s.empty?
42
- env["HTTP_AUTHORIZATION"]
43
- end
44
-
45
30
  def route_setting
46
31
  context.route_setting(:oauth2)
47
32
  end
@@ -50,54 +35,6 @@ module AuthenticJwt
50
35
  return unless route_setting
51
36
  route_setting.fetch(:scope, nil)
52
37
  end
53
-
54
- def bearer_token
55
- return unless authorization_header
56
- if authorization_header =~ BEARER_PATTERN
57
- result = Regexp.last_match(1)
58
- unless result.to_s.empty?
59
- result
60
- end
61
- end
62
- end
63
-
64
- def public_key
65
- result = ENV[PUBLIC_KEY_ENV_VAR].to_s
66
- return if result.empty?
67
- OpenSSL::PKey::RSA.new(result)
68
- end
69
-
70
- def jwt_payload
71
- return unless bearer_token
72
- return unless public_key
73
- payload, header = JWT.decode(bearer_token, public_key, true, algorithm: "RS512")
74
- payload
75
- end
76
-
77
- def account_id
78
- result = ENV[ACCOUNT_ID_ENV_VAR].to_s
79
- return if result.empty?
80
- result
81
- end
82
-
83
- def account_payload
84
- return unless jwt_payload
85
- jwt_payload["accounts"].detect { |account| account["aud"] == account_id }
86
- end
87
-
88
- def account_roles
89
- return [] unless account_payload
90
- account_payload["roles"].collect(&:downcase)
91
- end
92
-
93
- def acceptable_roles
94
- return [] unless scope
95
- case scope
96
- when "read" then AuthenticJwt::Role.read
97
- when "write" then AuthenticJwt::Role.write
98
- else raise ArgumentError
99
- end
100
- end
101
38
  end
102
39
  end
103
40
  end
@@ -0,0 +1,66 @@
1
+ require "openssl"
2
+ require "jwt"
3
+
4
+ module AuthenticJwt
5
+ class Validator
6
+ def initialize(public_key: ENV["AUTHENTIC_AUTH_PUBLIC_KEY"])
7
+ if public_key.to_s.empty?
8
+ raise Unauthorized, "JWT public key not present"
9
+ end
10
+
11
+ @public_key = OpenSSL::PKey::RSA.new(public_key.to_s)
12
+ end
13
+
14
+ def call(header:)
15
+ if header.to_s.empty?
16
+ raise Unauthorized, "Authorization header missing"
17
+ end
18
+
19
+ bearer_token = extract_bearer_token(header: header)
20
+
21
+ extract_payload(bearer_token: bearer_token)
22
+ end
23
+
24
+ protected
25
+
26
+ BEARER_PATTERN = /Bearer (.+)/
27
+ ALGORITHM = "RS512"
28
+
29
+ attr_reader :public_key
30
+
31
+ def extract_bearer_token(header:)
32
+ if header =~ BEARER_PATTERN
33
+ bearer_token = Regexp.last_match(1)
34
+ else
35
+ raise Unauthorized, "Authorization header is not a Bearer token"
36
+ end
37
+
38
+ if bearer_token.to_s.empty?
39
+ raise Unauthorized, "Bearer token not present"
40
+ end
41
+
42
+ bearer_token
43
+ end
44
+
45
+ def extract_payload(bearer_token:)
46
+ raw, header = begin
47
+ JWT.decode(bearer_token, public_key, true, algorithm: ALGORITHM)
48
+ rescue JWT::DecodeError => error
49
+ if error.message =~ /Signature verification raised/
50
+ raise Unauthorized, "JWT does not match signature"
51
+ else
52
+ raise Unauthorized, "Bearer token is not a valid JWT"
53
+ end
54
+ end
55
+
56
+ # TODO bypass this step
57
+ json = JSON.dump(raw)
58
+
59
+ begin
60
+ Payload.decode_json(json)
61
+ rescue Google::Protobuf::ParseError
62
+ raise Unauthorized, "JWT is not in the correct format"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,3 +1,3 @@
1
1
  module AuthenticJwt
2
- VERSION = "0.0.4".freeze
2
+ VERSION = "0.0.5".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authentic-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Authentic Limited
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-06 00:00:00.000000000 Z
11
+ date: 2017-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf
@@ -142,12 +142,14 @@ files:
142
142
  - bin/setup
143
143
  - definitions/payload.proto
144
144
  - lib/authentic-jwt.rb
145
+ - lib/authentic_jwt/authorizer.rb
145
146
  - lib/authentic_jwt/errors.rb
146
147
  - lib/authentic_jwt/grape/auth_methods.rb
147
148
  - lib/authentic_jwt/grape/extension.rb
148
149
  - lib/authentic_jwt/grape/middleware.rb
149
150
  - lib/authentic_jwt/payload_pb.rb
150
151
  - lib/authentic_jwt/role.rb
152
+ - lib/authentic_jwt/validator.rb
151
153
  - lib/authentic_jwt/version.rb
152
154
  homepage: https://github.com/mytours/authentic-jwt
153
155
  licenses: []
@@ -168,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
170
  version: '0'
169
171
  requirements: []
170
172
  rubyforge_project:
171
- rubygems_version: 2.6.8
173
+ rubygems_version: 2.5.2
172
174
  signing_key:
173
175
  specification_version: 4
174
176
  summary: Client authentication for Authentic Apps