virgil-jwt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,110 @@
1
+ # Copyright (C) 2015-2019 Virgil Security Inc.
2
+ #
3
+ # Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # (1) Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ #
14
+ # (2) Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in
16
+ # the documentation and/or other materials provided with the
17
+ # distribution.
18
+ #
19
+ # (3) Neither the name of the copyright holder nor the names of its
20
+ # contributors may be used to endorse or promote products derived from
21
+ # this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ # SERVICES; LOSS OF USE, bytes, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ # POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ module Virgil
36
+ module Jwt
37
+ # Represents content of [Jwt]
38
+ class JwtBodyContent
39
+ IDENTITY_PREFIX = 'identity-'.freeze
40
+ SUBJECT_PREFIX = 'virgil-'.freeze
41
+
42
+ # Jwt application id.
43
+ # @return [String]
44
+ attr_reader :app_id
45
+
46
+ # Jwt identity.
47
+ # @return [String]
48
+ attr_reader :identity
49
+
50
+ # Jwt issuer.
51
+ # @return [String]
52
+ attr_reader :issuer
53
+
54
+ # Jwt subject.
55
+ # @return [String]
56
+ attr_reader :subject
57
+
58
+ # When Jwt was issued.
59
+ # @return [Time]
60
+ attr_reader :issued_at
61
+
62
+ # When Jwt will expire.
63
+ # @return [Time]
64
+ attr_reader :expires_at
65
+
66
+ # Jwt additional data.
67
+ # @return [Hash]
68
+ attr_reader :additional_data
69
+
70
+ # Initializes a new instance of the class
71
+ # @param app_id [String] Application ID. Take it from {https://dashboard.virgilsecurity.com}
72
+ # @param identity [String] identity (must be equal to RawSignedModel identity when publishing card)
73
+ # @param issued_at [Time] issued data
74
+ # @param expires_at [Time] expiration date
75
+ # @param data [Hash] hash with additional data
76
+ def initialize(app_id:, identity:, issued_at:, expires_at:, data:)
77
+ @app_id = app_id
78
+ @identity = identity
79
+ @issued_at = issued_at
80
+ @expires_at = expires_at
81
+ @additional_data = data
82
+ @issuer = "#{SUBJECT_PREFIX}#{@app_id}"
83
+ @subject = "#{IDENTITY_PREFIX}#{@identity}"
84
+ end
85
+
86
+ # Json representation of body content
87
+ # @return [String]
88
+ def to_json
89
+ model = {
90
+ 'iss': issuer,
91
+ 'sub': subject,
92
+ 'iat': issued_at.to_i,
93
+ 'exp': expires_at.to_i,
94
+ 'ada': additional_data}
95
+ model.to_json
96
+ end
97
+
98
+ # Restore body content from json
99
+ # @return [JwtBodyContent]
100
+ def self.restore_from_json(str_json)
101
+ model = JSON.parse(str_json)
102
+ new(app_id: model['iss'].gsub(JwtBodyContent::SUBJECT_PREFIX, ''),
103
+ identity: model['sub'].gsub(JwtBodyContent::IDENTITY_PREFIX, ''),
104
+ issued_at: Time.at(model['iat']).utc,
105
+ expires_at: Time.at(model['exp']).utc,
106
+ data: model['ada'])
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,110 @@
1
+ # Copyright (C) 2015-2019 Virgil Security Inc.
2
+ #
3
+ # Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # (1) Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ #
14
+ # (2) Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in
16
+ # the documentation and/or other materials provided with the
17
+ # distribution.
18
+ #
19
+ # (3) Neither the name of the copyright holder nor the names of its
20
+ # contributors may be used to endorse or promote products derived from
21
+ # this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ # SERVICES; LOSS OF USE, bytes, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ # POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ module Virgil
36
+ module Jwt
37
+ class JwtGenerator
38
+
39
+ # Private Key which will be used for signing
40
+ # generated access tokens.
41
+ # Take it on {https://dashboard.virgilsecurity.com/api-keys}
42
+ # @return [PrivateKey]
43
+ attr_reader :api_key
44
+
45
+ # Key id of #api_key
46
+ # Take it on {https://dashboard.virgilsecurity.com/api-keys}
47
+ # @return [String]
48
+ attr_reader :api_public_key_id
49
+
50
+ # Application id
51
+ # Take it on {https://dashboard.virgilsecurity.com}
52
+ # @return [String]
53
+ attr_reader :app_id
54
+
55
+ # Lifetime of generated tokens in minutes
56
+ # @return [Integer]
57
+ attr_reader :life_time
58
+
59
+ # An instance of [AccessTokenSigner] that is used to
60
+ # generate token signature using #api_key
61
+ # @return [AccessTokenSigner]
62
+ attr_reader :access_token_signer
63
+
64
+ # Initializes a new instance of the class
65
+ # @param app_id [String] Application id
66
+ # Take it on {https://dashboard.virgilsecurity.com}
67
+ # @param api_key [PrivateKey] Private Key which will be used for signing
68
+ # generated access tokens. Take it on {https://dashboard.virgilsecurity.com/api-keys}
69
+ # @param api_public_key_id [String] Key id of #api_key.
70
+ # Take it on {https://dashboard.virgilsecurity.com/api-keys}
71
+ # @param life_time [Integer] Lifetime of generated tokens in minutes
72
+ # @param access_token_signer [AccessTokenSigner] An instance of [AccessTokenSigner]
73
+ # that is used to generate token signature using #api_key
74
+ def initialize(app_id:, api_key:, api_public_key_id:, life_time:, access_token_signer:)
75
+ @app_id = app_id
76
+ @api_key = api_key
77
+ @api_public_key_id = api_public_key_id
78
+ @life_time = life_time
79
+ @access_token_signer = access_token_signer
80
+ end
81
+
82
+ # Generates new JWT using specified identity and additional data.
83
+ # @param identity [String] identity to generate with.
84
+ # @param data [Hash] dictionary with additional data which will be kept in jwt body
85
+ # @return new instance of [Jwt]
86
+ def generate_token(identity, data = nil)
87
+ raise ArgumentError, 'Identity property is mandatory' if identity.nil?
88
+ issued_at = Time.now.utc
89
+ expires_at = Time.at(issued_at.to_i + @life_time * 60).utc
90
+ jwt_body = JwtBodyContent.new(app_id: @app_id,
91
+ issued_at: issued_at,
92
+ identity: identity,
93
+ expires_at: expires_at,
94
+ data: data)
95
+
96
+ jwt_header = JwtHeaderContent.new(algorithm: @access_token_signer.algorithm,
97
+ key_id: @api_public_key_id)
98
+ unsigned_jwt = Jwt.new(header_content: jwt_header,
99
+ body_content: jwt_body,
100
+ signature_data: nil)
101
+ jwt_bytes = Bytes.from_string(unsigned_jwt.to_s)
102
+ signature = @access_token_signer.generate_token_signature(jwt_bytes, @api_key)
103
+ Jwt.new(header_content: jwt_header,
104
+ body_content: jwt_body,
105
+ signature_data: signature)
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,94 @@
1
+ # Copyright (C) 2015-2019 Virgil Security Inc.
2
+ #
3
+ # Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # (1) Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ #
14
+ # (2) Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in
16
+ # the documentation and/or other materials provided with the
17
+ # distribution.
18
+ #
19
+ # (3) Neither the name of the copyright holder nor the names of its
20
+ # contributors may be used to endorse or promote products derived from
21
+ # this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ # SERVICES; LOSS OF USE, bytes, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ # POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ module Virgil
36
+ module Jwt
37
+ # Represents header of [Jwt]
38
+ class JwtHeaderContent
39
+ VIRGIL_CONTENT_TYPE = 'virgil-jwt;v=1'.freeze
40
+ JWT_TYPE = 'JWT'.freeze
41
+
42
+ # Signature algorithm
43
+ # @return [String]
44
+ attr_reader :algorithm
45
+
46
+ # Access token type.
47
+ # @return [String]
48
+ attr_reader :type
49
+
50
+ # Access token content type.
51
+ # @return [String]
52
+ attr_reader :content_type
53
+
54
+ # Id of public key which is used for jwt signature verification.
55
+ # @return [String]
56
+ attr_reader :key_id
57
+
58
+ # Initializes a new instance of the class
59
+ # @param algorithm [String] signature algorithm
60
+ # @param type [String] access token type
61
+ # @param content_type [String] Access token content type
62
+ # @param key_id [String] API key id. Take it from {https://dashboard.virgilsecurity.com/api-keys}
63
+ def initialize(algorithm:, key_id:, type: JWT_TYPE, content_type: VIRGIL_CONTENT_TYPE)
64
+ # todo validate
65
+ @algorithm = algorithm
66
+ @key_id = key_id
67
+ @type = type
68
+ @content_type = content_type
69
+ end
70
+
71
+ # Json representation of header content
72
+ # @return [String]
73
+ def to_json
74
+ model = {
75
+ 'alg': algorithm,
76
+ 'kid': key_id,
77
+ 'typ': type,
78
+ 'cty': content_type
79
+ }
80
+ model.to_json
81
+ end
82
+
83
+ # Restore header content from json
84
+ # @return [JwtHeaderContent]
85
+ def self.restore_from_json(str_json)
86
+ model = JSON.parse(str_json)
87
+ new(algorithm: model['alg'],
88
+ key_id: model['kid'],
89
+ type: model['typ'],
90
+ content_type: model['cty'])
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (C) 2015-2019 Virgil Security Inc.
2
+ #
3
+ # Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # (1) Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ #
14
+ # (2) Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in
16
+ # the documentation and/or other materials provided with the
17
+ # distribution.
18
+ #
19
+ # (3) Neither the name of the copyright holder nor the names of its
20
+ # contributors may be used to endorse or promote products derived from
21
+ # this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ # SERVICES; LOSS OF USE, bytes, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ # POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ module Virgil
36
+ module Jwt
37
+ class JwtVerifier
38
+
39
+ # @return [AccessTokenSigner] that is used to
40
+ # verify token signature.
41
+ attr_reader :access_token_signer
42
+
43
+ # Public Key which should be used to verify signatures
44
+ # @return [PublicKey]
45
+ attr_reader :api_public_key
46
+
47
+ # Id of public key which should be used to verify signatures
48
+ # @return [String]
49
+ attr_reader :api_public_key_id
50
+
51
+ # Initializes a new instance of the class
52
+ # @param access_token_signer [AccessTokenSigner]
53
+ # @param api_public_key [PublicKey]
54
+ # @param api_public_key_id [String]
55
+ def initialize(access_token_signer:, api_public_key:, api_public_key_id:)
56
+ @access_token_signer = access_token_signer
57
+ @api_public_key = api_public_key
58
+ @api_public_key_id = api_public_key_id
59
+ end
60
+
61
+ # Verifies specified token.
62
+ # @param jwt [Jwt] token to be virefied.
63
+ # @return true if token is verified, otherwise false.
64
+ def verify_token(jwt)
65
+ if jwt.header_content.key_id != @api_public_key_id ||
66
+ jwt.header_content.algorithm != @access_token_signer.algorithm ||
67
+ jwt.header_content.content_type != JwtHeaderContent::VIRGIL_CONTENT_TYPE ||
68
+ jwt.header_content.type != JwtHeaderContent::JWT_TYPE
69
+ return false
70
+ end
71
+
72
+ @access_token_signer.verify_token_signature(jwt.signature_data,
73
+ jwt.unsigned_data,
74
+ api_public_key)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,72 @@
1
+ # Copyright (C) 2015-2019 Virgil Security Inc.
2
+ #
3
+ # Lead Maintainer: Virgil Security Inc. <support@virgilsecurity.com>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are
9
+ # met:
10
+ #
11
+ # (1) Redistributions of source code must retain the above copyright
12
+ # notice, this list of conditions and the following disclaimer.
13
+ #
14
+ # (2) Redistributions in binary form must reproduce the above copyright
15
+ # notice, this list of conditions and the following disclaimer in
16
+ # the documentation and/or other materials provided with the
17
+ # distribution.
18
+ #
19
+ # (3) Neither the name of the copyright holder nor the names of its
20
+ # contributors may be used to endorse or promote products derived from
21
+ # this software without specific prior written permission.
22
+ #
23
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR
24
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ # DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27
+ # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ # SERVICES; LOSS OF USE, bytes, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33
+ # POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ module Virgil
36
+ module Jwt
37
+
38
+ # Provides payload for access token providers
39
+ class TokenContext
40
+
41
+ # Operation for which token is needed.
42
+ # @return [String]
43
+ attr_reader :operation
44
+
45
+ # Identity that should be used in access token.
46
+ # @return [String]
47
+ attr_reader :identity
48
+
49
+ # Service for which token is needed.
50
+ # @return [String]
51
+ attr_reader :service
52
+
53
+ # You can set up token cache in {CallbackJwtProvider#obtain_access_token_proc}
54
+ # and reset cached token if True.
55
+ # @return [TrueClass] or [FalseClass]
56
+ attr_reader :force_reload
57
+
58
+ # Initializes a new instance of the class
59
+ # @param operation [String] Operation for which token is needed
60
+ # @param identity [String] Identity to use in token
61
+ # @param force_reload [TrueClass] or [FalseClass]
62
+ # If you set up token cache in {CallbackJwtProvider#obtain_access_token_proc}
63
+ # it should reset cached token and return new if TRUE.
64
+ def initialize(operation:, identity:, service: nil, force_reload: false)
65
+ @operation = operation
66
+ @identity = identity
67
+ @service = service
68
+ @force_reload = force_reload
69
+ end
70
+ end
71
+ end
72
+ end