-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Preperations for version 2.x #49
Merged
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
a133496
Prepare splitting code into JWT, JWS and JWA
excpt b2631a0
Dropping mri 1.8 support, update configuration
excpt c21a0c9
Remove obsolete gems
excpt fe71b94
JWA HMAC implementation
excpt deb7dcb
JWA HMAC implementation
excpt 2717351
JWA RSASSA implementation
excpt 92ea937
JWA ECDSA implementation [in theory]
excpt af564c1
Enable travis-ci docker containers
excpt 277115e
JWA NONE implementation
excpt 816dbe5
Drop old ideas, restart at HS256 only
excpt e694fc4
Improve JWT::DecodeError exception output
excpt 9a20006
Add plain token handling
excpt a7d4fde
Add custom header test, remove unused variables
excpt 707b8e8
Remove old code
excpt d2e01d4
Initial JWA Implementation
excpt 1575512
Add first JWA HMAC logic
excpt 275638f
Extend JWA HMAC, break tests
excpt 5f660b8
Add Base64 encode and decode handling
excpt 7036713
Clean up code, add test for not implemented algorithms
excpt 64aa4f4
Fix some tests
excpt 621aaa6
Remove jwa folder from prepare-test script
excpt e432867
Remove skipped jwa folder on mkdir
excpt 9338632
Add new keys for tests
excpt d799c92
Add basic JWA RSASSA SHA implementation
excpt bd372df
Add test cases for wrong keys in RSASSA verification
excpt 0b0ff16
Integrate JWA into JWT
excpt 1be475d
Add SimpleCov config, improve coverage to 100%
excpt ada171f
Bunp version to 2.0.0.pre
excpt 10562e5
Add badges to README.md
excpt 33b65b9
Add ruby 2.2.0 for travis-ci testing
excpt 5a0eb5b
Update Gemfile, remove codeclimate from travis ci
excpt e0b2e6c
Update README.md
excpt 94b6788
Update README.md
excpt 7eef40e
Update README.md
excpt 8088bb1
Add codeclimate reporting fix provided by @jonathancadepowers
excpt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
/.idea | ||
/coverage | ||
/tmp | ||
*.iml | ||
jwt.gemspec | ||
pkg | ||
Gemfile.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--color |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
sudo: false | ||
language: ruby | ||
rvm: | ||
- 1.8.7 | ||
- 1.9.2 | ||
- 1.9.3 | ||
- 2.0.0 | ||
- 2.1.0 | ||
- jruby | ||
- rbx | ||
- ree | ||
script: "bundle exec rake test" | ||
- 2.1.5 | ||
- 2.2.0 | ||
script: "bundle exec rspec" | ||
before_install: | ||
- gem update --system | ||
- gem --version | ||
before_script: | ||
- bin/prepare-test.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,13 @@ | ||
source "https://rubygems.org" | ||
source 'https://rubygems.org' | ||
|
||
gem 'json', '>= 1.2.4' | ||
gem 'multi_json', '~> 1.0', :platforms => :ruby_18 | ||
gem 'jruby-openssl', :platforms => :jruby | ||
|
||
gem 'rubysl', '~> 2.0', :platforms => :rbx | ||
gem 'json' | ||
|
||
group :development do | ||
gem 'echoe', '>= 4.6.3' | ||
end | ||
|
||
group :test, :development do | ||
gem 'rake' | ||
gem 'rspec', '~> 3' | ||
gem 'rspec' | ||
gem 'codeclimate-test-reporter', require: false | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,21 @@ | ||
# JWT | ||
A Ruby implementation of [JSON Web Token draft 06](http://self-issued.info/docs/draft-jones-json-web-token-06.html). | ||
|
||
## Installing | ||
|
||
sudo gem install jwt | ||
|
||
## Usage | ||
# WARNING: This is the 2.x branch of ruby-jwt, currently under heavy development | ||
|
||
JWT.encode({"some" => "payload"}, "secret") | ||
# JWT | ||
|
||
Note the resulting JWT will not be encrypted, but verifiable with a secret key. | ||
[![Build Status](https://travis-ci.org/excpt/ruby-jwt.svg?branch=refactoring)](https://travis-ci.org/excpt/ruby-jwt) | ||
[![Codeship Status for excpt/moments](https://codeship.com/projects/f94b6890-6dc3-0132-8f82-52110d7a425c/status?branch=master)](https://codeship.com/projects/54274) | ||
[![Code Climate](https://codeclimate.com/github/excpt/ruby-jwt/badges/gpa.svg)](https://codeclimate.com/github/excpt/ruby-jwt) | ||
[![Test Coverage](https://codeclimate.com/github/excpt/ruby-jwt/badges/coverage.svg)](https://codeclimate.com/github/excpt/ruby-jwt) | ||
|
||
JWT.decode("someJWTstring", "secret") | ||
## Goal | ||
|
||
If the secret is wrong, it will raise a `JWT::DecodeError` telling you as such. You can still get at the payload by setting the verify argument to false. | ||
The goal is to implement the complete JWT spec including the underlying specs JWS, JWA, JWK and JWE. | ||
|
||
JWT.decode("someJWTstring", nil, false) | ||
* [JSON Web Token (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32) | ||
* [JSON Web Signature (JWS)](https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-39) | ||
* [JSON Web Encryption (JWE)](https://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-39) | ||
* [JSON Web Key (JWK)](https://tools.ietf.org/html/draft-ietf-jose-json-web-key-39) | ||
* [JSON Web Algorithms (JWA)](https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-39) | ||
|
||
## Algorithms | ||
|
||
|
@@ -33,16 +33,50 @@ The JWT spec supports several algorithms for cryptographic signing. This library | |
* RS384 - RSA using SHA-384 hash algorithm | ||
* RS512 - RSA using SHA-512 hash algorithm | ||
|
||
**NONE** | ||
|
||
* NONE - No signature | ||
|
||
## Installing | ||
|
||
```bash | ||
sudo gem install jwt | ||
``` | ||
|
||
## Usage | ||
|
||
Signing a JSON Web Token. | ||
|
||
```ruby | ||
JWT.encode({"some" => "payload"}, "secret") | ||
``` | ||
|
||
Note: The resulting JWT will not be encrypted, but verifiable with a secret key. | ||
|
||
```ruby | ||
JWT.decode("someJWTstring", "secret") | ||
``` | ||
|
||
If the secret is wrong, it will raise a `JWT::DecodeError` telling you as such. You can still get at the payload by setting the verify argument to false. | ||
|
||
```ruby | ||
JWT.decode("someJWTstring", nil, false) | ||
``` | ||
|
||
Change the algorithm with by setting it in encode: | ||
|
||
JWT.encode({"some" => "payload"}, "secret", "HS512") | ||
```ruby | ||
JWT.encode({"some" => "payload"}, "secret", "HS512") | ||
``` | ||
|
||
**Plaintext** | ||
|
||
We also support unsigned plaintext JWTs as introduced by draft 03 by explicitly specifying `nil` as the key and algorithm: | ||
|
||
jwt = JWT.encode({"some" => "payload"}, nil, nil) | ||
JWT.decode(jwt, nil, nil) | ||
```ruby | ||
jwt = JWT.encode({"some" => "payload"}, nil, nil) | ||
JWT.decode(jwt, nil, nil) | ||
``` | ||
|
||
## Support for reserved claim names | ||
JSON Web Token defines some reserved claim names and defines how they should be | ||
|
@@ -64,18 +98,21 @@ From [draft 01 of the JWT spec](http://self-issued.info/docs/draft-jones-json-we | |
|
||
You pass the expiration time as a UTC UNIX timestamp (an int). For example: | ||
|
||
JWT.encode({"exp": 1371720939}, "secret") | ||
|
||
JWT.encode({"exp": Time.now.to_i()}, "secret") | ||
```ruby | ||
JWT.encode({"exp": 1371720939}, "secret") | ||
JWT.encode({"exp": Time.now.to_i()}, "secret") | ||
``` | ||
|
||
Expiration time is automatically verified in `JWT.decode()` and raises | ||
`JWT::ExpiredSignature` if the expiration time is in the past: | ||
|
||
begin | ||
JWT.decode("JWT_STRING", "secret") | ||
rescue JWT::ExpiredSignature | ||
# Signature has expired | ||
end | ||
```ruby | ||
begin | ||
JWT.decode("JWT_STRING", "secret") | ||
rescue JWT::ExpiredSignature | ||
# Signature has expired | ||
end | ||
``` | ||
|
||
Expiration time will be compared to the current UTC time (as given by | ||
`Time.now.to_i`), so be sure to use a UTC timestamp or datetime in encoding. | ||
|
@@ -88,21 +125,27 @@ For example, if you have a JWT payload with a expiration time set to 30 seconds | |
after creation but you know that sometimes you will process it after 30 seconds, | ||
you can set a leeway of 10 seconds in order to have some margin: | ||
|
||
jwt_payload = JWT.encode({'exp': Time.now.to_i + 30}, 'secret') | ||
sleep(32) | ||
# jwt_payload is now expired | ||
# But with some leeway, it will still validate | ||
JWT.decode(jwt_payload, 'secret', true, leeway=10) | ||
```ruby | ||
jwt_payload = JWT.encode({'exp': Time.now.to_i + 30}, 'secret') | ||
sleep(32) | ||
# jwt_payload is now expired | ||
# But with some leeway, it will still validate | ||
JWT.decode(jwt_payload, 'secret', true, leeway=10) | ||
``` | ||
|
||
## Development and Tests | ||
|
||
We depend on [Echoe](http://rubygems.org/gems/echoe) for defining gemspec and performing releases to rubygems.org, which can be done with | ||
|
||
rake release | ||
```bash | ||
rake release | ||
``` | ||
|
||
The tests are written with rspec. Given you have rake and rspec, you can run tests with | ||
|
||
rake test | ||
```bash | ||
rake test | ||
``` | ||
|
||
**If you want a release cut with your PR, please include a version bump according to [Semantic Versioning](http://semver.org/)** | ||
|
||
|
@@ -118,6 +161,7 @@ The tests are written with rspec. Given you have rake and rspec, you can run tes | |
* Ariel Salomon (Oscil8) | ||
* Paul Battley <[email protected]> | ||
* Zane Shannon [@zshannon](https://github.com/zshannon) | ||
* Tim Rudat <[email protected]> [@excpt](https://github.com/excpt) | ||
|
||
## License | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,16 +2,16 @@ require 'rubygems' | |
require 'rake' | ||
require 'echoe' | ||
|
||
Echoe.new('jwt', '1.2.0') do |p| | ||
p.description = "JSON Web Token implementation in Ruby" | ||
p.url = "http://github.com/progrium/ruby-jwt" | ||
p.author = "Jeff Lindsay" | ||
p.email = "[email protected]" | ||
p.ignore_pattern = ["tmp/*"] | ||
p.development_dependencies = ["echoe >=4.6.3"] | ||
p.licenses = "MIT" | ||
Echoe.new('jwt', '2.0.0.pre') do |p| | ||
p.description = 'JSON Web Token implementation in Ruby' | ||
p.url = 'http://github.com/progrium/ruby-jwt' | ||
p.author = 'Jeff Lindsay' | ||
p.email = '[email protected]' | ||
p.ignore_pattern = ['tmp/*'] | ||
p.development_dependencies = ['echoe >=4.6.3'] | ||
p.licenses = 'MIT' | ||
end | ||
|
||
task :test do | ||
sh "rspec spec/jwt_spec.rb" | ||
sh 'bundle exec rspec' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/bin/sh | ||
|
||
rm -rf tmp/certs/*.pem | ||
|
||
mkdir -p tmp/certs | ||
|
||
# RSA KEYS | ||
openssl genrsa 1024 > tmp/certs/rsa-1024-private.pem | ||
openssl rsa -in tmp/certs/rsa-1024-private.pem -pubout > tmp/certs/rsa-1024-public.pem | ||
openssl genrsa 2048 > tmp/certs/rsa-2048-private.pem | ||
openssl genrsa 2048 > tmp/certs/rsa-2048-wrong-private.pem | ||
openssl rsa -in tmp/certs/rsa-2048-private.pem -pubout > tmp/certs/rsa-2048-public.pem | ||
openssl rsa -in tmp/certs/rsa-2048-wrong-private.pem -pubout > tmp/certs/rsa-2048-wrong-public.pem | ||
openssl genrsa 4096 > tmp/certs/rsa-4096-private.pem | ||
openssl rsa -in tmp/certs/rsa-4096-private.pem -pubout > tmp/certs/rsa-4096-public.pem | ||
|
||
# ECDSA KEYS | ||
openssl ecparam -out tmp/certs/ec256-private.pem -name secp256k1 -genkey | ||
openssl ecparam -out tmp/certs/ec256-wrong-private.pem -name secp256k1 -genkey | ||
openssl ecparam -out tmp/certs/ec384-private.pem -name secp384r1 -genkey | ||
openssl ecparam -out tmp/certs/ec384-wrong-private.pem -name secp384r1 -genkey | ||
openssl ecparam -out tmp/certs/ec512-private.pem -name secp521r1 -genkey | ||
openssl ecparam -out tmp/certs/ec512-wrong-private.pem -name secp521r1 -genkey | ||
openssl ec -in tmp/certs/ec256-private.pem -pubout > tmp/certs/ec256-public.pem | ||
openssl ec -in tmp/certs/ec256-wrong-private.pem -pubout > tmp/certs/ec256-wrong-public.pem | ||
openssl ec -in tmp/certs/ec384-private.pem -pubout > tmp/certs/ec384-public.pem | ||
openssl ec -in tmp/certs/ec384-wrong-private.pem -pubout > tmp/certs/ec384-wrong-public.pem | ||
openssl ec -in tmp/certs/ec512-private.pem -pubout > tmp/certs/ec512-public.pem | ||
openssl ec -in tmp/certs/ec512-wrong-private.pem -pubout > tmp/certs/ec512-wrong-public.pem |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
require 'jwa/hmac' | ||
require 'jwa/none' | ||
require 'jwa/rsassa' | ||
|
||
module JWA | ||
extend self | ||
|
||
# The complete list of signing algorithms defined in the IETF JSON Web Algorithms (JWA) version 38 | ||
# https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-38#section-3.1 | ||
ALGORITHMS = %w(HS256 HS384 HS512 RS256 RS384 RS512 ES256 ES384 ES512 PS256 PS384 PS512 none) | ||
|
||
# raises if the payload is not a string | ||
class InvalidPayloadFormat < ArgumentError | ||
end | ||
|
||
# raises if a algorithm is called that is not defined in the specs | ||
# Info: all algorithms a case-sensitive | ||
class InvalidAlgorithm < ArgumentError | ||
end | ||
|
||
# raises if a secret or key is required but not provided in order to sign the data | ||
class MissingSecretOrKey < ArgumentError | ||
end | ||
|
||
# raises if a part of code is not implemented | ||
class NotImplemented < ArgumentError | ||
end | ||
|
||
def sign(algorithm, data, secret_or_private_key = '') | ||
algo, bits = validate_algorithm algorithm | ||
validate_data data | ||
|
||
case algo | ||
when 'HS' | ||
JWA::HMAC.new(bits).sign(data, secret_or_private_key) | ||
when 'RS' | ||
JWA::RSASSA.new(bits).sign(data, secret_or_private_key) | ||
when 'none' | ||
JWA::NONE.new.sign() | ||
else | ||
raise JWA::NotImplemented.new("JWA: #{algorithm} is not implemented yet.") | ||
end | ||
end | ||
|
||
def verify(algorithm, data, signature, secret_or_public_key = '') | ||
algo, bits = validate_algorithm algorithm | ||
validate_data data | ||
|
||
case algo | ||
when 'HS' | ||
JWA::HMAC.new(bits).verify(data, signature, secret_or_public_key) | ||
when 'RS' | ||
JWA::RSASSA.new(bits).verify(data, signature, secret_or_public_key) | ||
when 'none' | ||
JWA::NONE.new.verify() | ||
else | ||
raise JWA::NotImplemented.new("JWA: #{algorithm} is not implemented yet.") | ||
end | ||
end | ||
|
||
def validate_algorithm(algorithm) | ||
raise JWA::InvalidAlgorithm.new("JWA: Given algorithm [#{algorithm.to_s}] is not part of the JWS supported algorithms.") unless ALGORITHMS.include? algorithm | ||
|
||
match = algorithm.match(/(HS|RS|ES|PS|none)(\d+)?/) | ||
|
||
[match[1], match[2]] | ||
end | ||
|
||
private :validate_algorithm | ||
|
||
def validate_data(data) | ||
raise JWA::InvalidPayloadFormat.new('JWA: Given data is not a string.') unless data.is_a? String | ||
end | ||
|
||
private :validate_data | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module JWA | ||
class HMAC | ||
def initialize(bits) | ||
@bits = bits | ||
end | ||
|
||
def sign(data, secret) | ||
validate_secret secret | ||
|
||
signature = OpenSSL::HMAC.digest OpenSSL::Digest.new("sha#{@bits}"), secret, data | ||
|
||
JWT::Base64.encode signature | ||
end | ||
|
||
def verify(data, signature, secret) | ||
signature === sign(data, secret) | ||
end | ||
|
||
def validate_secret(secret) | ||
raise JWA::MissingSecretOrKey.new('JWA: HMAC signing always requires a secret to be set.') if secret.length == 0 | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module JWA | ||
class NONE | ||
def sign | ||
'' | ||
end | ||
|
||
def verify | ||
true | ||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm just nitpicking here but in the code blocks throughout the README you're using different hash syntaxes, double and single quotes etc.
Since Ruby 1.8 is removed in that PR how about replacing all of these with the short notation?
(e.g.
{ exp: Time.now.to_i }
)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. I will change this and update the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. :)