Skip to content

Commit 74f0db1

Browse files
committed
implement saml provider
1 parent 4fe67cc commit 74f0db1

File tree

5 files changed

+105
-1
lines changed

5 files changed

+105
-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)

code0-identities.gemspec

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ 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

36+
spec.add_development_dependency "webmock", "~> 3.23.1"
3637
spec.add_development_dependency "rake", "~> 13.0"
3738
spec.add_development_dependency "rspec", "~> 3.0"
3839
spec.add_development_dependency "rubocop", "~> 1.21"

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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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], { **config[:response_settings], settings: create_settings })
22+
attributes = response.attributes
23+
24+
Identity.new(config[:provider_name],
25+
response.name_id,
26+
find_attribute(attributes, config[:attribute_statements][:username]),
27+
find_attribute(attributes, config[:attribute_statements][:email]),
28+
find_attribute(attributes, config[:attribute_statements][:firstname]),
29+
find_attribute(attributes, config[:attribute_statements][:lastname])
30+
)
31+
end
32+
33+
private
34+
35+
def find_attribute(attributes, attribute_statements)
36+
attribute_statements.each do |statement|
37+
unless attributes[statement].nil?
38+
return attributes[statement]
39+
end
40+
end
41+
nil
42+
end
43+
44+
def create_settings
45+
if config[:metadata_url].nil?
46+
settings = OneLogin::RubySaml::Settings.new
47+
else
48+
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
49+
settings = idp_metadata_parser.parse_remote(config[:metadata_url])
50+
end
51+
52+
settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
53+
54+
config[:settings].each do |key, value|
55+
settings.send(:"#{key}=", value)
56+
end
57+
settings
58+
end
59+
60+
def config
61+
config = config_loader
62+
if config_loader.is_a?(Proc)
63+
config = config_loader.call
64+
end
65+
66+
config[:provider_name] ||= :saml
67+
config[:response_settings] ||= {}
68+
config[:settings] ||= {}
69+
config[:attribute_statements] ||= {}
70+
config[:attribute_statements][:username] ||= %w[username name http://schemas.goauthentik.io/2021/02/saml/username]
71+
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]
72+
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]
73+
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]
74+
75+
config
76+
end
77+
end
78+
end
79+
end
80+
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)