Skip to content

Commit 6748fd5

Browse files
authored
Merge pull request #9 from code0-tech/providers/saml
implement saml provider
2 parents 309d969 + fcb8eea commit 6748fd5

File tree

6 files changed

+104
-1
lines changed

6 files changed

+104
-1
lines changed

Gemfile.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ PATH
33
specs:
44
code0-identities (0.0.0)
55
httparty (~> 0.22)
6+
ruby-saml (~> 1.17.0)
67

78
GEM
89
remote: https://rubygems.org/
@@ -24,8 +25,14 @@ GEM
2425
json (2.7.2)
2526
language_server-protocol (3.17.0.3)
2627
mini_mime (1.1.5)
28+
mini_portile2 (2.8.8)
2729
multi_xml (0.7.1)
2830
bigdecimal (~> 3.1)
31+
nokogiri (1.16.7)
32+
mini_portile2 (~> 2.8.2)
33+
racc (~> 1.4)
34+
nokogiri (1.16.7-x86_64-linux)
35+
racc (~> 1.4)
2936
parallel (1.25.1)
3037
parser (3.3.4.0)
3138
ast (~> 2.4.1)
@@ -77,6 +84,9 @@ GEM
7784
rubocop-rspec_rails (2.28.3)
7885
rubocop (~> 1.40)
7986
ruby-progressbar (1.13.0)
87+
ruby-saml (1.17.0)
88+
nokogiri (>= 1.13.10)
89+
rexml
8090
strscan (3.1.0)
8191
unicode-display_width (2.5.0)
8292
webmock (3.23.1)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ OAuth:
1010
- Microsoft
1111
- Github
1212
- Gitlab
13+
- SAML
1314

1415
## Installation
1516

code0-identities.gemspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ Gem::Specification.new do |spec|
3131
spec.require_paths = ["lib"]
3232

3333
spec.add_dependency "httparty", "~> 0.22"
34-
spec.add_development_dependency "webmock", "~> 3.23.1"
34+
spec.add_dependency "ruby-saml", "~> 1.17.0"
3535

3636
spec.add_development_dependency "rake", "~> 13.0"
3737
spec.add_development_dependency "rspec", "~> 3.0"
3838
spec.add_development_dependency "rubocop", "~> 1.21"
3939
spec.add_development_dependency "rubocop-rake", "~> 0.6"
4040
spec.add_development_dependency "rubocop-rspec", "~> 2.29" # Uncomment to register a new dependency of your gem
41+
spec.add_development_dependency "webmock", "~> 3.23.1"
4142
spec.metadata["rubygems_mfa_required"] = "true"
4243
end

lib/code0/identities.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require "httparty"
4+
require "onelogin/ruby-saml"
45

56
require_relative "identities/version"
67
require_relative "identities/identity_provider"
@@ -10,6 +11,7 @@
1011
require_relative "identities/provider/google"
1112
require_relative "identities/provider/discord"
1213
require_relative "identities/provider/github"
14+
require_relative "identities/provider/saml"
1315

1416
module Code0
1517
module Identities

lib/code0/identities/provider/saml.rb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)