Skip to content

Commit

Permalink
Merge pull request #9 from code0-tech/providers/saml
Browse files Browse the repository at this point in the history
implement saml provider
  • Loading branch information
Knerio authored Dec 12, 2024
2 parents 309d969 + fcb8eea commit 6748fd5
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 1 deletion.
10 changes: 10 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ PATH
specs:
code0-identities (0.0.0)
httparty (~> 0.22)
ruby-saml (~> 1.17.0)

GEM
remote: https://rubygems.org/
Expand All @@ -24,8 +25,14 @@ GEM
json (2.7.2)
language_server-protocol (3.17.0.3)
mini_mime (1.1.5)
mini_portile2 (2.8.8)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
nokogiri (1.16.7)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
parallel (1.25.1)
parser (3.3.4.0)
ast (~> 2.4.1)
Expand Down Expand Up @@ -77,6 +84,9 @@ GEM
rubocop-rspec_rails (2.28.3)
rubocop (~> 1.40)
ruby-progressbar (1.13.0)
ruby-saml (1.17.0)
nokogiri (>= 1.13.10)
rexml
strscan (3.1.0)
unicode-display_width (2.5.0)
webmock (3.23.1)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ OAuth:
- Microsoft
- Github
- Gitlab
- SAML

## Installation

Expand Down
3 changes: 2 additions & 1 deletion code0-identities.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]

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

spec.add_development_dependency "rake", "~> 13.0"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "rubocop", "~> 1.21"
spec.add_development_dependency "rubocop-rake", "~> 0.6"
spec.add_development_dependency "rubocop-rspec", "~> 2.29" # Uncomment to register a new dependency of your gem
spec.add_development_dependency "webmock", "~> 3.23.1"
spec.metadata["rubygems_mfa_required"] = "true"
end
2 changes: 2 additions & 0 deletions lib/code0/identities.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "httparty"
require "onelogin/ruby-saml"

require_relative "identities/version"
require_relative "identities/identity_provider"
Expand All @@ -10,6 +11,7 @@
require_relative "identities/provider/google"
require_relative "identities/provider/discord"
require_relative "identities/provider/github"
require_relative "identities/provider/saml"

module Code0
module Identities
Expand Down
78 changes: 78 additions & 0 deletions lib/code0/identities/provider/saml.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# frozen_string_literal: true

module Code0
module Identities
module Provider
class Saml
attr_reader :config_loader

def initialize(config_loader)
@config_loader = config_loader
end

def authorization_url
request = OneLogin::RubySaml::Authrequest.new
request.create(create_settings)

request.instance_variable_get :@login_url
end

def load_identity(**params)
response = OneLogin::RubySaml::Response.new(params[:SAMLResponse],
{ **config[:response_settings], settings: create_settings })
attributes = response.attributes

Identity.new(config[:provider_name],
response.name_id,
find_attribute(attributes, config[:attribute_statements][:username]),
find_attribute(attributes, config[:attribute_statements][:email]),
find_attribute(attributes, config[:attribute_statements][:firstname]),
find_attribute(attributes, config[:attribute_statements][:lastname]))
end

private

def find_attribute(attributes, attribute_statements)
attribute_statements.each do |statement|
return attributes[statement] unless attributes[statement].nil?
end
nil
end

def create_settings
if config[:metadata_url].nil?
settings = OneLogin::RubySaml::Settings.new
else
idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
settings = idp_metadata_parser.parse_remote(config[:metadata_url])
end

settings.name_identifier_format = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"

config[:settings].each do |key, value|
settings.send(:"#{key}=", value)
end
settings
end

def config
config = config_loader
config = config_loader.call if config_loader.is_a?(Proc)

# rubocop:disable Layout/LineLength
config[:provider_name] ||= :saml
config[:response_settings] ||= {}
config[:settings] ||= {}
config[:attribute_statements] ||= {}
config[:attribute_statements][:username] ||= %w[username name http://schemas.goauthentik.io/2021/02/saml/username]
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]
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]
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]
# rubocop:enable Layout/LineLength

config
end
end
end
end
end
11 changes: 11 additions & 0 deletions sig/code0/identities/provider/saml.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Code0
module Identities
module Provider
class Saml
def authorization_url: () -> String

def load_identity: (Hash[Symbol, any]) -> Identity
end
end
end
end

0 comments on commit 6748fd5

Please sign in to comment.