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 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=
@@ -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,10 @@
1
+ module Mumukit::Auth
2
+ class InvalidTokenError < StandardError
3
+ end
4
+
5
+ class UnauthorizedAccessError < StandardError
6
+ end
7
+
8
+ class EmailNotRegistered < StandardError
9
+ end
10
+ 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
@@ -0,0 +1,5 @@
1
+ module Mumukit
2
+ module Auth
3
+ VERSION = '0.2.3'
4
+ end
5
+ 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: []