code0-identities 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d2f9b0245b49ef731da01ee5592ffcb56c6211c478752fd8ec91690fe91372a
4
- data.tar.gz: f55736bb0f4c49734b2ae95d93414ed514833131bed57bc7aeedf487a5766bef
3
+ metadata.gz: c123702886210d5646bd8b5bc8090334e2b4c4cd66a5c6cc2b016f30405d8ec2
4
+ data.tar.gz: 6d0829ce20accd660c8e478c85e3b5600ecd395495887d73266c5cd6070ac852
5
5
  SHA512:
6
- metadata.gz: 390747996b868eb0db1558af9da5f64f55efc232f2e6bfa54b26b03df5e0bc828fab1fd5b61db9c279c59c4ccb63f3346fb04b893089076ccb39930908421b19
7
- data.tar.gz: 75dee3614cc0ce7e361e40105333049fd947243417b32c6ab4647e94b821c462d2a841cb9f267fdcd83f281f8bbf58704fd678c0d0ecddf305b89338f1fcdc13
6
+ metadata.gz: 20a9b75f381cc363ff01d094f1058a3564047ea7e7b94bf2ece6314b87867daa64d700eb8b698510089d15786234816de57376a20d72660c3a70bf33e93ea28e
7
+ data.tar.gz: da743a997b959429bc8ec815075aba4a4f920036721de6932567425f4ca35ff3daf36bd09a22eb789892d1acd2e9be67e7419fcfb7bf49bc17b08506020213a7
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ require:
3
3
  - rubocop-rspec
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 3.0.0
6
+ TargetRubyVersion: 3.2.0
7
7
  NewCops: enable
8
8
 
9
9
  Gemspec/DevelopmentDependencies:
@@ -38,6 +38,9 @@ RSpec/ExampleLength:
38
38
  Style/Documentation:
39
39
  Enabled: false
40
40
 
41
+ Style/HashSyntax:
42
+ EnforcedShorthandSyntax: never
43
+
41
44
  RSpec/MultipleMemoizedHelpers:
42
45
  Enabled: false
43
46
  RSpec/MultipleExpectations:
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.2.2
1
+ ruby 3.4.7
data/README.md CHANGED
@@ -10,6 +10,8 @@ OAuth:
10
10
  - Microsoft
11
11
  - Github
12
12
  - Gitlab
13
+ - OIDC / oAuth2
14
+ - SAML
13
15
 
14
16
  ## Installation
15
17
 
@@ -91,4 +93,43 @@ def fetch_configuration
91
93
  }
92
94
  end
93
95
 
94
- ```
96
+ ```
97
+
98
+ # Configuration
99
+
100
+ As you already know, we allow / require to pass in a configuration. Here are all avaiable configuration keys:
101
+
102
+
103
+ ## Oauth Based:
104
+ Here is the updated table where each key in the JSON (`identifier`, `username`, etc.) is explicitly labeled:
105
+
106
+ | Name | Description | Default |
107
+ |------------------------------------|--------------------------------------------------------------------------------------------|-----------------------------------------------------|
108
+ | `client_id` | The client id of the application (needs to be set) | **(no default specified)** |
109
+ | `client_secret` | The client secret of the application (needs to be set) | **(no default specified)** |
110
+ | `redirect_uri` | The redirect URL of the application (needs to be set) | **(no default specified)** |
111
+ | `provider_name` | The provider name (not necessarily) | depends on the provider (e.g., `discord`, `github`) |
112
+ | `user_details_url` | The user details URL to gather user information (only for OIDC) | **(no default specified)** |
113
+ | `authorization_url` | The URL which the user has to access to authorize (only for OIDC) | **(no default specified)** |
114
+ | `attribute_statements` | The keys which the response of the user details has (id, name, email, ...) (only for OIDC) | `{}` (see below for more) |
115
+ | `attribute_statements.identifier` | The identifier of the user to identify (only for OIDC) | `["id", "sub", "identifier"]` |
116
+ | `attribute_statements.username` | The username of the user (only for OIDC) | `["username", "name", "login"]` |
117
+ | `attribute_statements.email` | The email address of the user (only for OIDC) | `["email", "mail"]` |
118
+ | `attribute_statements.firstname` | The first name of the user (only for OIDC) | `["first_name", "firstname", ...]` |
119
+ | `attribute_statements.lastname` | The last name of the user (only for OIDC) | `["last_name", "lastname", ...]` |
120
+
121
+ ## SAML
122
+
123
+ | Name | Description | Default |
124
+ |----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------|
125
+ | `provider_name` | The provider name (not necessarily) | `saml` |
126
+ | `attribute_statements` | The keys which the response of the user details has (id, name, email, ...) (only for OIDC) | `{}` (see below for more) |
127
+ | `attribute_statements.username` | The username of the user | `["username", "name", ...]` |
128
+ | `attribute_statements.email` | The email address of the user | `["email", "mail", ...]` |
129
+ | `attribute_statements.firstname` | The first name of the user | `["first_name", "firstname", ...]` |
130
+ | `attribute_statements.lastname` | The last name of the user | `["last_name", "lastname", ...]` |
131
+ | `settings` | The settings to configure the saml response/requests (see [SAML-Toolkits#L200](https://github.com/SAML-Toolkits/ruby-saml/blob/master/README.md?plain=1#L200)) | `{}` |
132
+ | `response_settings` | The response settings to disable some checks if you want (see [SAML-Toolkits#L234](https://github.com/SAML-Toolkits/ruby-saml/blob/master/README.md?plain=1#L234)) | `{}` |
133
+ | `metadata_url` | The metadata url to fetch the metadatas (replacement for `settings`) | **(no default specified)** |
134
+
135
+
@@ -68,9 +68,12 @@ module Code0
68
68
  end
69
69
 
70
70
  def config
71
- return config_loader.call if config_loader.is_a?(Proc)
71
+ config = config_loader
72
+ config = config_loader.call if config_loader.is_a?(Proc)
72
73
 
73
- config_loader
74
+ config[:provider_name] ||= self.class.name.downcase.split("::").last
75
+
76
+ config
74
77
  end
75
78
  end
76
79
  end
@@ -31,7 +31,7 @@ module Code0
31
31
  username = body["username"]
32
32
  email = body["email"]
33
33
 
34
- Identity.new(:discord, identifier, username, email, nil, nil)
34
+ Identity.new(config[:provider_name], identifier, username, email, nil, nil)
35
35
  end
36
36
  end
37
37
  end
@@ -43,7 +43,7 @@ module Code0
43
43
 
44
44
  email = private_email(access_token, token_type) if email.nil?
45
45
 
46
- Identity.new(:github, identifier, username, email, nil, nil)
46
+ Identity.new(config[:provider_name], identifier, username, email, nil, nil)
47
47
  end
48
48
  end
49
49
  end
@@ -37,7 +37,7 @@ module Code0
37
37
  username = body["username"]
38
38
  email = body["email"]
39
39
 
40
- Identity.new(config_loader.call[:provider_name], identifier, username, email, nil, nil)
40
+ Identity.new(config[:provider_name], identifier, username, email, nil, nil)
41
41
  end
42
42
  end
43
43
  end
@@ -41,7 +41,7 @@ module Code0
41
41
  firstname = body["given_name"]
42
42
  lastname = body["family_name"]
43
43
 
44
- Identity.new(:google, identifier, username, email, firstname, lastname)
44
+ Identity.new(config[:provider_name], identifier, username, email, firstname, lastname)
45
45
  end
46
46
  end
47
47
  end
@@ -36,7 +36,7 @@ module Code0
36
36
  lastname = body["familyname"]
37
37
  email = body["email"]
38
38
 
39
- Identity.new(:microsoft, identifier, nil, email, firstname, lastname)
39
+ Identity.new(config[:provider_name], identifier, nil, email, firstname, lastname)
40
40
  end
41
41
  end
42
42
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Code0
4
+ module Identities
5
+ module Provider
6
+ class Oidc < BaseOauth
7
+ def token_url
8
+ config[:token_url]
9
+ end
10
+
11
+ def token_payload(code)
12
+ { code: code,
13
+ grant_type: "authorization_code",
14
+ redirect_uri: config[:redirect_uri],
15
+ client_id: config[:client_id],
16
+ client_secret: config[:client_secret] }
17
+ end
18
+
19
+ def user_details_url
20
+ config[:user_details_url]
21
+ end
22
+
23
+ def authorization_url
24
+ config[:authorization_url]
25
+ .gsub("{client_id}", config[:client_id])
26
+ .gsub("{redirect_uri}", config[:redirect_uri])
27
+ end
28
+
29
+ def create_identity(response, *)
30
+ body = response.parsed_response
31
+
32
+ Identity.new(config[:provider_name],
33
+ find_attribute(body, config[:attribute_statements][:identifier]),
34
+ find_attribute(body, config[:attribute_statements][:username]),
35
+ find_attribute(body, config[:attribute_statements][:email]),
36
+ find_attribute(body, config[:attribute_statements][:firstname]),
37
+ find_attribute(body, config[:attribute_statements][:lastname]))
38
+ end
39
+
40
+ def config
41
+ config = super
42
+
43
+ # rubocop:disable Layout/LineLength
44
+ config[:provider_name] ||= :oidc
45
+ config[:attribute_statements] ||= {}
46
+ config[:attribute_statements][:identifier] ||= %w[sub id identifier]
47
+ config[:attribute_statements][:username] ||= %w[username name login]
48
+ config[:attribute_statements][:email] ||= %w[email mail]
49
+ config[:attribute_statements][:firstname] ||= %w[first_name firstname firstName givenname given_name givenName]
50
+ config[:attribute_statements][:lastname] ||= %w[last_name lastname lastName family_name familyName familyname]
51
+ # rubocop:enable Layout/LineLength
52
+
53
+ config
54
+ end
55
+
56
+ def find_attribute(attributes, attribute_statements)
57
+ attribute_statements.each do |statement|
58
+ return attributes[statement] unless attributes[statement].nil?
59
+ end
60
+ nil
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Code0
4
+ module Identities
5
+ module Provider
6
+ class Saml
7
+ attr_reader :config_loader
8
+
9
+ def initialize(config_loader)
10
+ @config_loader = config_loader
11
+ end
12
+
13
+ def authorization_url
14
+ request = OneLogin::RubySaml::Authrequest.new
15
+ request.create(create_settings)
16
+
17
+ request.instance_variable_get :@login_url
18
+ end
19
+
20
+ def load_identity(**params)
21
+ response = OneLogin::RubySaml::Response.new(params[:SAMLResponse],
22
+ { **config[:response_settings], settings: create_settings })
23
+ attributes = response.attributes
24
+
25
+ Identity.new(config[:provider_name],
26
+ response.name_id,
27
+ find_attribute(attributes, config[:attribute_statements][:username]),
28
+ find_attribute(attributes, config[:attribute_statements][:email]),
29
+ find_attribute(attributes, config[:attribute_statements][:firstname]),
30
+ find_attribute(attributes, config[:attribute_statements][:lastname]))
31
+ end
32
+
33
+ private
34
+
35
+ def find_attribute(attributes, attribute_statements)
36
+ attribute_statements.each do |statement|
37
+ return attributes[statement] unless attributes[statement].nil?
38
+ end
39
+ nil
40
+ end
41
+
42
+ def create_settings
43
+ if config[:metadata_url].nil?
44
+ settings = OneLogin::RubySaml::Settings.new
45
+ else
46
+ idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
47
+ settings = idp_metadata_parser.parse_remote(config[:metadata_url])
48
+ end
49
+
50
+ settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
51
+
52
+ config[:settings].each do |key, value|
53
+ settings.send(:"#{key}=", value)
54
+ end
55
+ settings
56
+ end
57
+
58
+ def config
59
+ config = config_loader
60
+ config = config_loader.call if config_loader.is_a?(Proc)
61
+
62
+ # rubocop:disable Layout/LineLength
63
+ config[:provider_name] ||= :saml
64
+ config[:response_settings] ||= {}
65
+ config[:settings] ||= {}
66
+ config[:attribute_statements] ||= {}
67
+ config[:attribute_statements][:username] ||= %w[username name http://schemas.goauthentik.io/2021/02/saml/username]
68
+ config[:attribute_statements][:email] ||= %w[email mail http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress http://schemas.microsoft.com/ws/2008/06/identity/claims/emailaddress]
69
+ config[:attribute_statements][:firstname] ||= %w[first_name firstname firstName http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname http://schemas.microsoft.com/ws/2008/06/identity/claims/givenname]
70
+ config[:attribute_statements][:lastname] ||= %w[last_name lastname lastName http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname http://schemas.microsoft.com/ws/2008/06/identity/claims/surname]
71
+ # rubocop:enable Layout/LineLength
72
+
73
+ config
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Code0
4
4
  module Identities
5
- VERSION = "0.0.1"
5
+ VERSION = "0.0.2"
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "httparty"
4
+ require "onelogin/ruby-saml"
4
5
 
5
6
  require_relative "identities/version"
6
7
  require_relative "identities/identity_provider"
@@ -10,6 +11,8 @@ require_relative "identities/provider/microsoft"
10
11
  require_relative "identities/provider/google"
11
12
  require_relative "identities/provider/discord"
12
13
  require_relative "identities/provider/github"
14
+ require_relative "identities/provider/oidc"
15
+ require_relative "identities/provider/saml"
13
16
 
14
17
  module Code0
15
18
  module Identities
data/renovate.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
3
  "extends": [
4
- "config:recommended",
5
- ":label(dependencies)"
4
+ "github>code0-tech/monoceros//renovate/global.json5"
6
5
  ],
7
6
  "assignees": [
8
7
  "Taucher2003",
@@ -0,0 +1,17 @@
1
+ module Code0
2
+ module Identities
3
+ module Provider
4
+ class Oidc < BaseOauth
5
+ def token_url: () -> String
6
+
7
+ def token_payload: (code: String) -> { code: String, grant_type: "authorization_code", redirect_uri: String, client_id: String, client_secret: String }
8
+
9
+ def user_details_url: () -> String
10
+
11
+ def authorization_url: () -> String
12
+
13
+ def create_identity: (response: Net::HTTPResponse) -> Identity
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module Code0
2
+ module Identities
3
+ module Provider
4
+ class Saml
5
+ def authorization_url: () -> String
6
+
7
+ def load_identity: (Hash[Symbol, any]) -> Identity
8
+ end
9
+ end
10
+ end
11
+ end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code0-identities
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dario Pranjic
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-08-29 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.3.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.3.0
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: httparty
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -25,19 +38,19 @@ dependencies:
25
38
  - !ruby/object:Gem::Version
26
39
  version: '0.22'
27
40
  - !ruby/object:Gem::Dependency
28
- name: webmock
41
+ name: ruby-saml
29
42
  requirement: !ruby/object:Gem::Requirement
30
43
  requirements:
31
44
  - - "~>"
32
45
  - !ruby/object:Gem::Version
33
- version: 3.23.1
34
- type: :development
46
+ version: '1.18'
47
+ type: :runtime
35
48
  prerelease: false
36
49
  version_requirements: !ruby/object:Gem::Requirement
37
50
  requirements:
38
51
  - - "~>"
39
52
  - !ruby/object:Gem::Version
40
- version: 3.23.1
53
+ version: '1.18'
41
54
  - !ruby/object:Gem::Dependency
42
55
  name: rake
43
56
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +121,20 @@ dependencies:
108
121
  - - "~>"
109
122
  - !ruby/object:Gem::Version
110
123
  version: '2.29'
111
- description:
124
+ - !ruby/object:Gem::Dependency
125
+ name: webmock
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 3.23.1
131
+ type: :development
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: 3.23.1
112
138
  email:
113
139
  - dpranjic@code0.tech
114
140
  executables: []
@@ -130,6 +156,8 @@ files:
130
156
  - lib/code0/identities/provider/gitlab.rb
131
157
  - lib/code0/identities/provider/google.rb
132
158
  - lib/code0/identities/provider/microsoft.rb
159
+ - lib/code0/identities/provider/oidc.rb
160
+ - lib/code0/identities/provider/saml.rb
133
161
  - lib/code0/identities/version.rb
134
162
  - renovate.json
135
163
  - sig/code0/identities.rbs
@@ -141,6 +169,8 @@ files:
141
169
  - sig/code0/identities/provider/gitlab.rbs
142
170
  - sig/code0/identities/provider/google.rbs
143
171
  - sig/code0/identities/provider/microsoft.rbs
172
+ - sig/code0/identities/provider/oidc.rbs
173
+ - sig/code0/identities/provider/saml.rbs
144
174
  - sig/code0/identities/version.rbs
145
175
  homepage: https://github.com/code0-tech/code0-identities
146
176
  licenses:
@@ -150,7 +180,6 @@ metadata:
150
180
  source_code_uri: https://github.com/code0-tech/code0-identities
151
181
  changelog_uri: https://github.com/code0-tech/code0-identities/releases
152
182
  rubygems_mfa_required: 'true'
153
- post_install_message:
154
183
  rdoc_options: []
155
184
  require_paths:
156
185
  - lib
@@ -158,15 +187,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
187
  requirements:
159
188
  - - ">="
160
189
  - !ruby/object:Gem::Version
161
- version: 3.0.0
190
+ version: 3.2.0
162
191
  required_rubygems_version: !ruby/object:Gem::Requirement
163
192
  requirements:
164
193
  - - ">="
165
194
  - !ruby/object:Gem::Version
166
195
  version: '0'
167
196
  requirements: []
168
- rubygems_version: 3.4.10
169
- signing_key:
197
+ rubygems_version: 3.6.9
170
198
  specification_version: 4
171
199
  summary: Library to manage external identities
172
200
  test_files: []