mumukit-auth 0.2.3
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.
- checksums.yaml +15 -0
- data/lib/mumukit/auth.rb +25 -0
- data/lib/mumukit/auth/exceptions.rb +10 -0
- data/lib/mumukit/auth/grant.rb +76 -0
- data/lib/mumukit/auth/metadata.rb +56 -0
- data/lib/mumukit/auth/permissions.rb +58 -0
- data/lib/mumukit/auth/token.rb +69 -0
- data/lib/mumukit/auth/user.rb +67 -0
- data/lib/mumukit/auth/version.rb +5 -0
- metadata +150 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OWI4N2M5NDExZDc1NjhjYTQ2NjMwNGRmZjFjZmY1ZjI0NWM5MDVlNg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NDJjMTc0ZmMzODc2NThjNGNjYmNjNjRiNDgyZDAxYzExN2RkMzJkMQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YTU3YjdjN2VlZGY0N2RmZWM1ZTNkOTg0YjE3YTdiZTE5MmQ0ZjI0YTY2NmYy
|
10
|
+
OWNkOGUyNjdkZTIzYmFiNzUyNGQ4MGMwMGExZGE0Mzk5Y2VhMTRhMDU2ZWVi
|
11
|
+
ZDY5MjMyMDJiZmFiMTNjNTgxNzQ2NTE3NTk4NDNmZTg0OGY0MGU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTFjM2UxMTc4MmRiZjQ0ZWExYTRlYThiNzIyNDcxNjgzNjk3YjUwYjdhMzFm
|
14
|
+
YmU5NzM5ZWFiNzdkZDRiOWJmNmU2OTM2ZTRhYmNjZTA0NDgxYTUyMjdlYzU1
|
15
|
+
NWI2NjdhZDVlYzEzZDZjOGE1NjczMGE5ZWQwZDEwOTAxMjAyOTQ=
|
data/lib/mumukit/auth.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'mumukit/core'
|
3
|
+
|
4
|
+
require_relative './auth/version'
|
5
|
+
require_relative './auth/exceptions'
|
6
|
+
require_relative './auth/grant'
|
7
|
+
require_relative './auth/metadata'
|
8
|
+
require_relative './auth/token'
|
9
|
+
require_relative './auth/permissions'
|
10
|
+
require_relative './auth/user'
|
11
|
+
|
12
|
+
require 'ostruct'
|
13
|
+
|
14
|
+
module Mumukit
|
15
|
+
module Auth
|
16
|
+
def self.configure
|
17
|
+
@config ||= OpenStruct.new
|
18
|
+
yield @config
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.config
|
22
|
+
@config
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Mumukit::Auth
|
2
|
+
class Grant
|
3
|
+
def as_json(options={})
|
4
|
+
to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](resource)
|
8
|
+
(self.class.slug? resource) ? allows?(resource) : access?(resource)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.slug?(resource_identifier)
|
12
|
+
/.*\/.*/.matches? resource_identifier
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse(pattern)
|
16
|
+
case pattern
|
17
|
+
when '*' then
|
18
|
+
AllGrant.new
|
19
|
+
when /(.*)\/\*/
|
20
|
+
OrgGrant.new($1)
|
21
|
+
else
|
22
|
+
SingleGrant.new(pattern)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class AllGrant < Grant
|
28
|
+
def allows?(slug)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def access?(organization)
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
'*'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class SingleGrant < Grant
|
42
|
+
def initialize(slug)
|
43
|
+
@slug = slug
|
44
|
+
end
|
45
|
+
|
46
|
+
def allows?(slug)
|
47
|
+
@slug == slug
|
48
|
+
end
|
49
|
+
|
50
|
+
def access?(organization)
|
51
|
+
@slug.split('/')[0] == organization
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
@slug
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class OrgGrant < Grant
|
60
|
+
def initialize(org)
|
61
|
+
@org = org
|
62
|
+
end
|
63
|
+
|
64
|
+
def allows?(slug)
|
65
|
+
/^#{@org}\/.*/.matches? slug
|
66
|
+
end
|
67
|
+
|
68
|
+
def access?(organization)
|
69
|
+
@org == organization
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
"#{@org}/*"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class Mumukit::Auth::Metadata
|
2
|
+
def initialize(json)
|
3
|
+
@json = json
|
4
|
+
end
|
5
|
+
|
6
|
+
def as_json(_options={})
|
7
|
+
@json
|
8
|
+
end
|
9
|
+
|
10
|
+
def permissions(app)
|
11
|
+
@json.dig(app, 'permissions').to_mumukit_auth_permissions
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_permission!(app, permission)
|
15
|
+
if permissions(app).present?
|
16
|
+
@json[app] = process_permission(app, permission)
|
17
|
+
else
|
18
|
+
@json.merge!("#{app}" => {'permissions' => permission})
|
19
|
+
end
|
20
|
+
@json
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_permission(app, permission)
|
24
|
+
{permissions: Mumukit::Auth::Permissions.load(permissions(app).as_json + ":#{permission}").to_s}
|
25
|
+
end
|
26
|
+
|
27
|
+
def librarian?(slug)
|
28
|
+
has_role? 'bibliotheca', slug
|
29
|
+
end
|
30
|
+
|
31
|
+
def admin?(slug)
|
32
|
+
has_role? 'admin', slug
|
33
|
+
end
|
34
|
+
|
35
|
+
def teacher?(slug)
|
36
|
+
has_role? 'classroom', slug
|
37
|
+
end
|
38
|
+
|
39
|
+
def student?(slug)
|
40
|
+
has_role? 'atheneum', slug
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.load(json)
|
44
|
+
new(JSON.parse(json))
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.dump(metadata)
|
48
|
+
metadata.to_json
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def has_role?(app, slug)
|
54
|
+
permissions(app)[slug]
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Mumukit::Auth
|
2
|
+
class Permissions
|
3
|
+
|
4
|
+
def initialize(grants)
|
5
|
+
@grants = grants
|
6
|
+
end
|
7
|
+
|
8
|
+
def protect!(slug)
|
9
|
+
raise Mumukit::Auth::UnauthorizedAccessError.new(unauthorized_message(slug)) unless allows?(slug)
|
10
|
+
end
|
11
|
+
|
12
|
+
def allows?(slug)
|
13
|
+
any_grant? { |grant| grant.allows? slug }
|
14
|
+
end
|
15
|
+
|
16
|
+
def access?(organization)
|
17
|
+
any_grant? { |grant| grant.access? organization }
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](organization)
|
21
|
+
any_grant? { |grant| grant[organization] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def as_json
|
25
|
+
to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@grants.map(&:to_s).uniq.join(':')
|
30
|
+
end
|
31
|
+
|
32
|
+
def present?
|
33
|
+
to_s.present?
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.dump(permission)
|
37
|
+
permission.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.load(pattern)
|
41
|
+
parse(pattern)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.parse(pattern)
|
45
|
+
new(pattern.split(':').map { |grant_pattern| Grant.parse(grant_pattern) })
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def any_grant?(&block)
|
51
|
+
@grants.any?(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def unauthorized_message(slug)
|
55
|
+
"Unauthorized access to #{slug}. Permissions are #{to_s}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'jwt'
|
2
|
+
|
3
|
+
module Mumukit::Auth
|
4
|
+
class Token
|
5
|
+
attr_reader :jwt
|
6
|
+
|
7
|
+
def initialize(jwt)
|
8
|
+
@jwt = jwt
|
9
|
+
end
|
10
|
+
|
11
|
+
def metadata
|
12
|
+
@metadata ||= Mumukit::Auth::Metadata.new(jwt['app_metadata'] || {})
|
13
|
+
end
|
14
|
+
|
15
|
+
def permissions(app)
|
16
|
+
metadata.permissions(app)
|
17
|
+
end
|
18
|
+
|
19
|
+
def verify_client!
|
20
|
+
raise Mumukit::Auth::InvalidTokenError.new('aud mismatch') if Mumukit::Auth.config.client_id != jwt['aud']
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.from_env(env)
|
24
|
+
new(env.dig('omniauth.auth', 'extra', 'raw_info') || {})
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.decode_header(header)
|
28
|
+
raise Mumukit::Auth::InvalidTokenError.new('missing authorization header') if header.nil?
|
29
|
+
decode header.split(' ').last
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.decode(encoded)
|
33
|
+
Token.new JWT.decode(encoded, decoded_secret)[0]
|
34
|
+
rescue JWT::DecodeError => e
|
35
|
+
raise Mumukit::Auth::InvalidTokenError.new(e)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.encode_dummy_auth_header(metadata)
|
39
|
+
encoded_token = JWT.encode(
|
40
|
+
{aud: Mumukit::Auth.config.client_id,
|
41
|
+
app_metadata: metadata},
|
42
|
+
decoded_secret)
|
43
|
+
'dummy token ' + encoded_token
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.decoded_secret
|
47
|
+
JWT.base64url_decode(Mumukit::Auth.config.client_secret)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
class Permissions
|
53
|
+
def to_mumukit_auth_permissions
|
54
|
+
self
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class String
|
60
|
+
def to_mumukit_auth_permissions
|
61
|
+
Mumukit::Auth::Permissions.parse(self)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class NilClass
|
66
|
+
def to_mumukit_auth_permissions
|
67
|
+
Mumukit::Auth::Permissions.new([])
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'auth0'
|
2
|
+
|
3
|
+
class Mumukit::Auth::User
|
4
|
+
|
5
|
+
attr_accessor :social_id, :user
|
6
|
+
|
7
|
+
def initialize(social_id, user=nil)
|
8
|
+
@social_id = social_id
|
9
|
+
@user = user || client.user(@social_id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def update_permissions(key, permission)
|
13
|
+
metadata.add_permission!(key, permission)
|
14
|
+
client.update_user_metadata social_id, metadata.as_json
|
15
|
+
end
|
16
|
+
|
17
|
+
def permissions_string
|
18
|
+
apps.select { |app| @user[app].present? }.map { |app| {app.to_s => @user[app]} }.reduce({}, :merge).to_json
|
19
|
+
end
|
20
|
+
|
21
|
+
def metadata
|
22
|
+
@metadata ||= Mumukit::Auth::Metadata.load(permissions_string)
|
23
|
+
end
|
24
|
+
|
25
|
+
def permissions_for(app)
|
26
|
+
metadata[app]['permissions']
|
27
|
+
end
|
28
|
+
|
29
|
+
def apps
|
30
|
+
['bibliotheca', 'classroom', 'admin', 'atheneum']
|
31
|
+
end
|
32
|
+
|
33
|
+
def client
|
34
|
+
self.class.client
|
35
|
+
end
|
36
|
+
|
37
|
+
def librarian?(slug)
|
38
|
+
metadata.librarian? slug
|
39
|
+
end
|
40
|
+
|
41
|
+
def admin?(slug)
|
42
|
+
metadata.admin? slug
|
43
|
+
end
|
44
|
+
|
45
|
+
def teacher?(slug)
|
46
|
+
metadata.teacher? slug
|
47
|
+
end
|
48
|
+
|
49
|
+
def student?(slug)
|
50
|
+
metadata.student? slug
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.from_email(email)
|
54
|
+
user = client.users("email:#{email}").first
|
55
|
+
raise Mumukit::Auth::EmailNotRegistered.new('There is no user registered with that email.') unless user.present?
|
56
|
+
new(user['user_id'])
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.client
|
60
|
+
Auth0Client.new(
|
61
|
+
:client_id => ENV['MUMUKI_AUTH0_CLIENT_ID'],
|
62
|
+
:client_secret => ENV['MUMUKI_AUTH0_CLIENT_SECRET'],
|
63
|
+
:domain => "mumuki.auth0.com"
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mumukit-auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Franco Leonardo Bulgarelli
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: jwt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: auth0
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mumukit-core
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.1'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.1'
|
111
|
+
description:
|
112
|
+
email:
|
113
|
+
- franco@mumuki.org
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/mumukit/auth.rb
|
119
|
+
- lib/mumukit/auth/exceptions.rb
|
120
|
+
- lib/mumukit/auth/grant.rb
|
121
|
+
- lib/mumukit/auth/metadata.rb
|
122
|
+
- lib/mumukit/auth/permissions.rb
|
123
|
+
- lib/mumukit/auth/token.rb
|
124
|
+
- lib/mumukit/auth/user.rb
|
125
|
+
- lib/mumukit/auth/version.rb
|
126
|
+
homepage: http://github.com/mumuki/mumukit-auth
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.4.5
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Library for authenticating mumuki requests
|
150
|
+
test_files: []
|