jwt-rest 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6229e085830cca4899bfa9ef248f02d8ad7fca11
4
+ data.tar.gz: ef6d83d44c95ae05d62ff1a766761a3ac1e8fe8c
5
+ SHA512:
6
+ metadata.gz: c1a9043a63577267151a44f191249b12945ffde205baddd09c4fffa4773b1a40bbcd693beb08b11e759dda3170ec67efe8b0d07a69d7a7bd3ab60d66156b120f
7
+ data.tar.gz: '0900893019db66dbf674673896d4115b64d6c0ec9ce6765f967c872f1738d25b9cf19492b908c5ca19131740aa36c0b0623be5fb126e5b321c09b1a735fa54dd'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2018 mariowise
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # jwt-rest
2
+
3
+ ## Installation
4
+ Add this line to your application's Gemfile:
5
+
6
+ ```ruby
7
+ gem 'jwt-rest'
8
+ ```
9
+
10
+ And then execute:
11
+ ```bash
12
+ $ bundle
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ First you will need to provide a way to find if the ApiKey is valid or not, and a way to retrieve the RSA private key to sign JWT tokens. For this, lets create a initializer `config/initializers/jwt_rest.rb`.
18
+
19
+ ```
20
+ require "jwt_rest"
21
+
22
+ module JwtRest
23
+ module Secrets
24
+ def self.rsa_private_key
25
+ # return he Base64 encoded of your RSA private key
26
+ end
27
+
28
+ def self.valid_api_key?(api_key)
29
+ # return true if the api_key is valid
30
+ end
31
+ end
32
+ end
33
+ ```
34
+
35
+ Then in your API's base controller do this
36
+
37
+ ```
38
+ class ApiController < ActionController::API
39
+ include JwtRest::Authenticable
40
+
41
+ before_action :demand_application_json
42
+ before_action :demand_api_key
43
+
44
+ def handle_user_identity(jwt_payload)
45
+ return false unless @current_user = User.find_by(email: jwt_payload.dig("email"))
46
+ true
47
+ end
48
+ end
49
+ ```
50
+
51
+ This will ensure that every call to your API i
52
+ s made with a valid api key. You could use the method `demand_current_user` for those endpoins where you need to authenticate the user with the JWT token.
53
+
54
+ ```
55
+ class UsersController < ApiController
56
+ before_action :demand_current_user, only: [:profile]
57
+
58
+ def profile
59
+ # here we have the @current_user variable
60
+ end
61
+ end
62
+ ```
63
+
64
+ ## Contributing
65
+ Contribution directions go here.
66
+
67
+ ### TODO
68
+
69
+ * Multiple RSA algorithm types for the JWT token
70
+
71
+ ## License
72
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Jwt::Rest'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+
33
+ task default: :test
@@ -0,0 +1,25 @@
1
+ module JwtRest
2
+ class AuthHeader
3
+ def initialize(chunk = "")
4
+ @type, @value = chunk.split(" ")
5
+ @type = @type&.downcase
6
+ end
7
+
8
+ def is_basic?
9
+ type == "basic"
10
+ end
11
+
12
+ def is_token?
13
+ type == "bearer"
14
+ end
15
+
16
+ def token
17
+ return JwtRest::Tokens::Basic.new(token: value).load_token if is_basic?
18
+ return JwtRest::Tokens::Jwt.new(token: value).load_token if is_token?
19
+ end
20
+
21
+ private
22
+
23
+ attr_accessor :type, :value
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module JwtRest
2
+ module Authenticable
3
+ def demand_application_json
4
+ unless request.format.symbol == :json
5
+ render status: :not_acceptable, json: { error: "only application/json Content-Tyle is allowed" }
6
+ end
7
+ end
8
+
9
+ def demand_api_key
10
+ api_key = request.headers["HTTP_X_API_KEY"]
11
+ unless JwtRest::Secrets.valid_api_key?(api_key)
12
+ render status: :unauthorized, json: { error: "invalid api key" }
13
+ end
14
+ end
15
+
16
+ def demand_current_user
17
+ header = JwtRest::AuthHeader.new(request.headers["HTTP_AUTHORIZATION"])
18
+ unless header.is_token? && header.token && handle_user_identity(header.token.payload)
19
+ render status: :unauthorized, json: { error: "invalid authorization token" }
20
+ end
21
+ end
22
+
23
+ # To be defined by the developer
24
+ # def handle_user_identity(jwt_payload)
25
+ # true if the users is valid
26
+ # end
27
+
28
+ attr_reader :current_user
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module JwtRest
2
+ module Secrets
3
+ def self.rsa_private_key
4
+ raise "You should override this method and provide the Base64 encoded of your RSA private key"
5
+ end
6
+
7
+ def self.valid_api_key?(api_key)
8
+ raise "You should override this method and provide a way to verify your API_KEYs"
9
+ end
10
+
11
+ def self.rsa_private
12
+ pkey = rsa_private_key
13
+ begin
14
+ decoded = Base64.decode64(pkey)
15
+ OpenSSL::PKey::RSA.new(decoded)
16
+ rescue
17
+ raise "Unable to decode your private key. Be sure to provide a valid RSA private key and then apply the Base64 encoding"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ module JwtRest
2
+ module Tokens
3
+ class Basic
4
+ attr_reader :username, :password, :token
5
+
6
+ def initialize(username: nil, password: nil, token: nil)
7
+ @username = username
8
+ @password = password
9
+ @token = token
10
+ end
11
+
12
+ def load_token
13
+ @username, @password = decoder(@token).split(":")
14
+ self
15
+ end
16
+
17
+ def load_credentials
18
+ @token = encoder("#{username}:#{password}")
19
+ self
20
+ end
21
+
22
+ def encoder(target)
23
+ Base64.encode64(target).gsub("\n", "")
24
+ end
25
+
26
+ def decoder(target)
27
+ Base64.decode64(target)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ module JwtRest
2
+ module Tokens
3
+ class JwtRest::Tokens::Jwt
4
+ attr_reader :payload, :token
5
+
6
+ def initialize(payload: nil, token: nil)
7
+ @payload = payload || {}
8
+ @token = token
9
+ end
10
+
11
+ def load_payload
12
+ @payload[:exp] = default_exp unless @payload[:exp]
13
+ @token = JWT.encode(payload, key, 'RS384')
14
+ self
15
+ end
16
+
17
+ def load_token
18
+ parts = JWT.decode(token, key.public_key, true, { algorithm: 'RS384' })
19
+ @payload = parts.reduce({}, :merge)
20
+ self
21
+ end
22
+
23
+ private
24
+
25
+ def key
26
+ JwtRest::Secrets.rsa_private
27
+ end
28
+
29
+ def default_exp
30
+ (Time.now + 24 * 3600).to_i
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module JwtRest
2
+ VERSION = "0.1.0"
3
+ end
data/lib/jwt_rest.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "jwt"
2
+ require "jwt_rest/version"
3
+ require "jwt_rest/secrets"
4
+ require "jwt_rest/tokens/basic"
5
+ require "jwt_rest/tokens/jwt"
6
+ require "jwt_rest/auth_header"
7
+ require "jwt_rest/authenticable"
8
+
9
+ module JwtRest
10
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :jwt_rest do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jwt-rest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - mariowise
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-05-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: jwt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: A security layer for any API REST in Rails with JWT tokens.
84
+ email:
85
+ - mariolopezlandes@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - MIT-LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/jwt_rest.rb
94
+ - lib/jwt_rest/auth_header.rb
95
+ - lib/jwt_rest/authenticable.rb
96
+ - lib/jwt_rest/secrets.rb
97
+ - lib/jwt_rest/tokens/basic.rb
98
+ - lib/jwt_rest/tokens/jwt.rb
99
+ - lib/jwt_rest/version.rb
100
+ - lib/tasks/jwt/rest_tasks.rake
101
+ homepage: https://github.com/mariowise/jwt-rest
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.5.1
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: A security layer for any API REST in Rails with JWT tokens.
125
+ test_files: []