rack_entra_id_auth 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +19 -0
- data/README.md +35 -0
- data/Rakefile +10 -0
- data/lib/generators/rack_entra_id_auth/initializer_generator.rb +13 -0
- data/lib/generators/rack_entra_id_auth/routes_generator.rb +15 -0
- data/lib/generators/rack_entra_id_auth/templates/config_initializer.rb +169 -0
- data/lib/rack_entra_id_auth/configuration.rb +80 -0
- data/lib/rack_entra_id_auth/entra_id_request.rb +240 -0
- data/lib/rack_entra_id_auth/middleware.rb +192 -0
- data/lib/rack_entra_id_auth/mock_middleware.rb +123 -0
- data/lib/rack_entra_id_auth/railtie.rb +19 -0
- data/lib/rack_entra_id_auth/version.rb +3 -0
- data/lib/rack_entra_id_auth.rb +14 -0
- metadata +144 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 49047b15ce1a63b8d78470a9f3470642bc1097ef848af57c588a105583ac5c08
|
4
|
+
data.tar.gz: 831a559681d4e4f17b837796bc670d93bbec3c148ac0f9ad868a72a2631df53c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b6e06a56cad6e71aa29e1191cec1a5e6d1c3f3a6c1080d2ed2fd2291de3af5ad3c0a41de393b72c26fb117b42490269a6c7b2eaeb65cb4e03fbf6a9cb5ee0ca5
|
7
|
+
data.tar.gz: a685bb6f5f8dae75f9153acfcb403594f8be4cd1ab1621b7abca4cbf97a04a55b53d4ce70c10a7b0803587816c3fbd6732d24b9ce65ebebbd1bdd62835ad9ba1
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2024 David Susco
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# EntraIdActiveRecordSessionStore
|
2
|
+
|
3
|
+
TODO: Delete this and the text below, and describe your gem
|
4
|
+
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/entra_id_active_record_session_store`. To experiment with that code, run `bin/console` for an interactive prompt.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
10
|
+
|
11
|
+
Install the gem and add to the application's Gemfile by executing:
|
12
|
+
|
13
|
+
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
14
|
+
|
15
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
|
+
|
17
|
+
$ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Development
|
24
|
+
|
25
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
26
|
+
|
27
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/entra_id_active_record_session_store.
|
32
|
+
|
33
|
+
## License
|
34
|
+
|
35
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module RackEntraIdAuth
|
2
|
+
module Generators
|
3
|
+
class InitializerGenerator < Rails::Generators::Base
|
4
|
+
desc 'Create an initializer to configure RackEntraIdAuth.'
|
5
|
+
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
def create_initializer
|
9
|
+
template 'config_initializer.rb', Rails.root.join('config', 'initializers', 'rack_entra_id_auth.rb')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RackEntraIdAuth
|
2
|
+
module Generators
|
3
|
+
class RoutesGenerator < Rails::Generators::Base
|
4
|
+
desc 'Create route helpers for single sign-on/logout requests handled by the RackEntraIdAuth middleware.'
|
5
|
+
|
6
|
+
def create_login_route
|
7
|
+
route "get '#{RackEntraIdAuth.config.login_path}', as: :login, to: ->(env) { [204, {}, ['']] }"
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_logout_route
|
11
|
+
route "get '#{RackEntraIdAuth.config.logout_path}', as: :logout, to: ->(env) { [204, {}, ['']] }"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
RackEntraIdAuth.configure do |config|
|
2
|
+
# Ruby SAML needs to be configured with the Entra ID application it will using
|
3
|
+
# as the Identify Provider (IdP) as well as your application that it will be
|
4
|
+
# using as the Service Provider (SP).
|
5
|
+
#
|
6
|
+
# All of the Ruby SAML settings are exposed as configuration attributes on the
|
7
|
+
# RackEntraIdAuth.config object and can be set from within this initializer or
|
8
|
+
# within `config/application.rb' or the environment-specific configuration
|
9
|
+
# files (e.g. config.rack_entra_id_auth.idp_entity_id = '…'). Any default
|
10
|
+
# settings defined by Ruby SAML are used by RackEntraIdAuth and called out
|
11
|
+
# below. They can also be found here:
|
12
|
+
# https://github.com/SAML-Toolkits/ruby-saml/blob/master/lib/onelogin/ruby-saml/settings.rb#L276
|
13
|
+
|
14
|
+
# ------------------------
|
15
|
+
# RackEntraIdAuth Settings
|
16
|
+
# ------------------------
|
17
|
+
|
18
|
+
# The login/logout paths are used by the middleware to create single
|
19
|
+
# sign-on/logout requests and redirect them to the IdP SSO/SLO Service URLs
|
20
|
+
# set below, respectively. It's handy to define these as routes in your
|
21
|
+
# application so you can use the route helpers in your views. You can do so
|
22
|
+
# with the `rack_entra_id_auth:routes` generator.
|
23
|
+
# config.login_path = '/login'
|
24
|
+
# config.logout_path = '/logout'
|
25
|
+
|
26
|
+
# By default, all the login/logout responses from the IdP are redirected to
|
27
|
+
# base URL of your application after the response is successfully processed
|
28
|
+
# and the user's session is set/deleted. If you'd like the user redirected to
|
29
|
+
# another URL upon successful login/logout this can be set below. These can
|
30
|
+
# also be overridden on a per-request basis by adding a `relay_state` query
|
31
|
+
# parameter to requests for the login/logout paths above, e.g.
|
32
|
+
# `http://your:app/login?relay_state=https%3A%2F%2Fyour.app%2Fgo_here_instead`
|
33
|
+
# config.login_relay_state_url = ''
|
34
|
+
# config.logout_relay_state_url = ''
|
35
|
+
|
36
|
+
# ----------------------------------------------------------------------------
|
37
|
+
# THIS SETTING HAS NO EFFECT IN AN INITIALIZER (it's set too late). It needs
|
38
|
+
# to be in `config/application.rb` or an environment-specific configuration
|
39
|
+
# file. You'll likely want to put it in in your
|
40
|
+
# `config/environments/production.rb` file as
|
41
|
+
# `config.rack_entra_id_auth.mock_server = false`.
|
42
|
+
# ----------------------------------------------------------------------------
|
43
|
+
# config.mock_server = false
|
44
|
+
|
45
|
+
# If mock_server is enabled these are the usernames you'll be able to log in
|
46
|
+
# as with the mock middleware, as well as the assoicatied "SAML" attributes
|
47
|
+
# that will be placed in the user's session.
|
48
|
+
# config.mock_attributes = {
|
49
|
+
# 'rtables' => {
|
50
|
+
# 'displayname' => 'Little Bobby Tables',
|
51
|
+
# 'groups' => ['Students'],
|
52
|
+
# 'givenname' => "Robert');DROP TABLE Students;-- ?",
|
53
|
+
# 'surname' => 'Tables',
|
54
|
+
# 'emailaddress' => 'rtables@your.app',
|
55
|
+
# 'name' => 'rtables@your.app'
|
56
|
+
# },
|
57
|
+
# 'badmin' => {
|
58
|
+
# 'displayname' => 'Bad Admin',
|
59
|
+
# 'groups' => ['Admins'],
|
60
|
+
# 'givenname' => 'Bad',
|
61
|
+
# 'surname' => 'Admin',
|
62
|
+
# 'emailaddress' => 'badmin@your.app',
|
63
|
+
# 'name' => 'badmin@your.app'
|
64
|
+
# }
|
65
|
+
# }
|
66
|
+
|
67
|
+
# The hash key the SAML attributes are stored under in the sessions hash.
|
68
|
+
# config.session_key = :entra_id
|
69
|
+
|
70
|
+
# The SAML attributes can be modified before they are stored within the user's
|
71
|
+
# session via the proc below. The following is the default proc.
|
72
|
+
# config.session_value_proc = Proc.new { |attributes|
|
73
|
+
# attributes.inject({}) do |memo, (key, value)|
|
74
|
+
# key = key.split('/').last
|
75
|
+
# value = value.first if value.kind_of?(Array) and value.length.eql?(1) and !key.eql?('groups')
|
76
|
+
# memo[key] = value
|
77
|
+
# memo
|
78
|
+
# end
|
79
|
+
# }
|
80
|
+
|
81
|
+
# Single logout requires changing the application's session store to work, so
|
82
|
+
# it is disabled by default. Once the session store is configured uncomment
|
83
|
+
# the line below to enable single logout.
|
84
|
+
# config.skip_single_logout = true
|
85
|
+
|
86
|
+
# ----------------------
|
87
|
+
# Ruby SAML IdP Settings
|
88
|
+
# ----------------------
|
89
|
+
|
90
|
+
# When the Entra ID application is set up you'll be provided with single sign-
|
91
|
+
# on/logout service URLs. RackEntraIdAuth needs these so it can direct the
|
92
|
+
# single sign-on/logout requests that originate from within your application.
|
93
|
+
# The public certificate provided by the IdP also needs to be in these
|
94
|
+
# requests and should be set below as well.
|
95
|
+
|
96
|
+
# config.idp_entity_id = ''
|
97
|
+
config.idp_sso_service_url = "IdP SINGLE SIGN-ON SERVICE URL"
|
98
|
+
config.idp_slo_service_url = "IdP SINGLE LOGOUT SERVICE URL"
|
99
|
+
# config.idp_slo_response_service_url = ''
|
100
|
+
config.idp_cert = 'IdP X509CERTIFICATE'
|
101
|
+
# config.idp_cert_fingerprint = ''
|
102
|
+
# config.idp_cert_fingerprint_algorithm = XMLSecurity::Document::SHA1
|
103
|
+
# config.idp_cert_multi = ''
|
104
|
+
# config.idp_attribute_names = ''
|
105
|
+
# config.idp_name_qualifier = ''
|
106
|
+
# config.valid_until = ''
|
107
|
+
|
108
|
+
# ---------------------
|
109
|
+
# Ruby SAML SP Settings
|
110
|
+
# ---------------------
|
111
|
+
|
112
|
+
# When the Entra ID application is set up you'll need to provide some way to
|
113
|
+
# identify your application (the SP) to it as well as the URLs your
|
114
|
+
# application will use to handle single sign-on/logout reseponses sent by the
|
115
|
+
# IdP to your application. Your application does not need to be aware of these
|
116
|
+
# URLs, the RackEntraIdAuth middleware will intercept and handle them.
|
117
|
+
# However, these URLs should not conflict with any routes within your
|
118
|
+
# application as requests sent to them will never make it to your application.
|
119
|
+
|
120
|
+
config.sp_entity_id = 'https://your.app/'
|
121
|
+
config.assertion_consumer_service_url = 'https://your.app/saml/login'
|
122
|
+
config.single_logout_service_url = 'https://your.app/saml/logout'
|
123
|
+
# config.sp_name_qualifier = ''
|
124
|
+
# config.name_identifier_format = ''
|
125
|
+
# config.name_identifier_value = ''
|
126
|
+
# config.name_identifier_value_requested = ''
|
127
|
+
# config.sessionindex = ''
|
128
|
+
# Ruby SAML normally compresses requests/responses and double quotes the XML
|
129
|
+
# attributes. Uncomment the lines below to change that.
|
130
|
+
# config.compress_request = false
|
131
|
+
# config.compress_response = false
|
132
|
+
# config.double_quote_xml_attribute_values = false
|
133
|
+
# config.message_max_bytesize = 250000
|
134
|
+
# config.passive = ''
|
135
|
+
# config.attributes_index = ''
|
136
|
+
# config.force_authn = ''
|
137
|
+
# config.certificate = ''
|
138
|
+
# config.private_key = ''
|
139
|
+
# config.sp_cert_multi = ''
|
140
|
+
# config.authn_context = ''
|
141
|
+
# config.authn_context_comparison = ''
|
142
|
+
# config.authn_context_decl_ref = ''
|
143
|
+
|
144
|
+
# ---------------------------
|
145
|
+
# Ruby SAML Workflow Settings
|
146
|
+
# ---------------------------
|
147
|
+
|
148
|
+
# The default Ruby SAML security configurations can be overriden by
|
149
|
+
# uncommenting the lines below.
|
150
|
+
# config.security = {
|
151
|
+
# :authn_requests_signed => true,
|
152
|
+
# :logout_requests_signed => true,
|
153
|
+
# :logout_responses_signed => true,
|
154
|
+
# :want_assertions_signed => true,
|
155
|
+
# :want_assertions_encrypted => true,
|
156
|
+
# :want_name_id => true,
|
157
|
+
# :metadata_signed => true,
|
158
|
+
# :digest_method => XMLSecurity::Document::SHA1,
|
159
|
+
# :signature_method => XMLSecurity::Document::RSA_SHA1,
|
160
|
+
# :check_idp_cert_expiration => true,
|
161
|
+
# :check_sp_cert_expiration => true,
|
162
|
+
# :strict_audience_validation => true,
|
163
|
+
# :lowercase_url_encoding => true
|
164
|
+
# }
|
165
|
+
|
166
|
+
# Ruby SAML normally doesn't raise SAML validation errors, uncomment the line
|
167
|
+
# below to raise them.
|
168
|
+
# config.soft = false
|
169
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'active_support/configurable'
|
2
|
+
|
3
|
+
module RackEntraIdAuth
|
4
|
+
class Configuration
|
5
|
+
include ActiveSupport::Configurable
|
6
|
+
|
7
|
+
config_accessor :login_path, default: '/login'
|
8
|
+
config_accessor :login_relay_state_url
|
9
|
+
config_accessor :logout_path, default: '/logout'
|
10
|
+
config_accessor :logout_relay_state_url
|
11
|
+
# mock_server must be set in `config/application.rb` or an environment-
|
12
|
+
# specific configuration file. I.e. it must happen before initializers as
|
13
|
+
# it's used in the initializer created in the Railtie.
|
14
|
+
config_accessor :mock_server, default: true
|
15
|
+
config_accessor :mock_attributes, default: {}
|
16
|
+
config_accessor :session_key, default: :entra_id
|
17
|
+
config_accessor :session_value_proc, default: Proc.new { |attributes|
|
18
|
+
attributes.inject({}) do |memo, (key, value)|
|
19
|
+
key = key.split('/').last
|
20
|
+
value = value.first if value.kind_of?(Array) and value.length.eql?(1) and !key.eql?('groups')
|
21
|
+
memo[key] = value
|
22
|
+
memo
|
23
|
+
end
|
24
|
+
}
|
25
|
+
config_accessor :skip_single_logout, default: true
|
26
|
+
|
27
|
+
# Ruby SAML ID Provider Settings
|
28
|
+
config_accessor :idp_entity_id
|
29
|
+
config_accessor :idp_sso_service_url
|
30
|
+
config_accessor :idp_slo_service_url
|
31
|
+
config_accessor :idp_slo_response_service_url
|
32
|
+
config_accessor :idp_cert
|
33
|
+
config_accessor :idp_cert_fingerprint
|
34
|
+
config_accessor :idp_cert_fingerprint_algorithm
|
35
|
+
config_accessor :idp_cert_multi
|
36
|
+
config_accessor :idp_attribute_names
|
37
|
+
config_accessor :idp_name_qualifier
|
38
|
+
config_accessor :valid_until
|
39
|
+
|
40
|
+
# Ruby SAML Service Provider Settings
|
41
|
+
config_accessor :sp_entity_id
|
42
|
+
config_accessor :assertion_consumer_service_url
|
43
|
+
config_accessor :single_logout_service_url
|
44
|
+
config_accessor :sp_name_qualifier
|
45
|
+
config_accessor :name_identifier_format
|
46
|
+
config_accessor :name_identifier_value
|
47
|
+
config_accessor :name_identifier_value_requested
|
48
|
+
config_accessor :sessionindex
|
49
|
+
config_accessor :compress_request
|
50
|
+
config_accessor :compress_response
|
51
|
+
config_accessor :double_quote_xml_attribute_values
|
52
|
+
config_accessor :message_max_bytesize
|
53
|
+
config_accessor :passive
|
54
|
+
config_accessor :attributes_index
|
55
|
+
config_accessor :force_authn
|
56
|
+
config_accessor :certificate
|
57
|
+
config_accessor :private_key
|
58
|
+
config_accessor :sp_cert_multi
|
59
|
+
config_accessor :authn_context
|
60
|
+
config_accessor :authn_context_comparison
|
61
|
+
config_accessor :authn_context_decl_ref
|
62
|
+
|
63
|
+
# Ruby SAML workflow Settings
|
64
|
+
config_accessor :security
|
65
|
+
config_accessor :soft
|
66
|
+
|
67
|
+
def ruby_saml_settings
|
68
|
+
config.to_h.except(
|
69
|
+
:login_path,
|
70
|
+
:login_relay_state_url,
|
71
|
+
:logout_path,
|
72
|
+
:logout_relay_state_url,
|
73
|
+
:mock_server,
|
74
|
+
:mock_attributes,
|
75
|
+
:session_key,
|
76
|
+
:session_value_proc,
|
77
|
+
:skip_single_logout)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'ruby-saml'
|
2
|
+
|
3
|
+
module RackEntraIdAuth
|
4
|
+
class EntraIdRequest
|
5
|
+
attr_reader :request
|
6
|
+
|
7
|
+
def initialize(request, saml_setting_overrides = {})
|
8
|
+
@request = request
|
9
|
+
|
10
|
+
@saml_settings = OneLogin::RubySaml::Settings.new(RackEntraIdAuth.config.ruby_saml_settings.merge(saml_setting_overrides))
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the request's base URL and path without the path_info at the end.
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
def base_url
|
18
|
+
"#{request.base_url}#{request.path}".sub(Regexp.new("#{request.path_info}$"), '')
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns whether the request is a Service Provider initiated sign-on
|
22
|
+
# request. Returns true if the request's path info equals the login path
|
23
|
+
# configuration (login_path), otherwise returns false.
|
24
|
+
#
|
25
|
+
# @return [Bool]
|
26
|
+
#
|
27
|
+
def login?
|
28
|
+
request.path_info.eql?(RackEntraIdAuth.config.login_path)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns whether the request contains a single sign-on response (for
|
32
|
+
# Service Provider initiated single sign-on requests). Returns true if the
|
33
|
+
# request's header contains a SAMLResponse and if the request's base_url and
|
34
|
+
# path match the ACS service url setting (assertion_consumer_service_url),
|
35
|
+
# otherwise returns false.
|
36
|
+
#
|
37
|
+
# @return [Bool]
|
38
|
+
#
|
39
|
+
def login_response?
|
40
|
+
saml_response.present? and "#{request.base_url}#{request.path}".eql?(@saml_settings.assertion_consumer_service_url)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns whether the request is a Service Provider initiated logout
|
44
|
+
# request. Returns true if the request's path info equals the logout path
|
45
|
+
# configuration (logout_path), otherwise returns false.
|
46
|
+
#
|
47
|
+
# @return [Bool]
|
48
|
+
#
|
49
|
+
def logout?
|
50
|
+
request.path_info.eql?(RackEntraIdAuth.config.logout_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns whether the request contains a single logout request (for ID
|
54
|
+
# Provider initiated single logout requests). Returns true if the request
|
55
|
+
# contains a SAMLRequest query parameter and if the request's base_url and
|
56
|
+
# path match the single logout service url setting
|
57
|
+
# (single_logout_service_url), otherwise returns false.
|
58
|
+
#
|
59
|
+
# @return [Bool]
|
60
|
+
#
|
61
|
+
def logout_request?
|
62
|
+
request.params['SAMLRequest'].present? and "#{request.base_url}#{request.path}".eql?(@saml_settings.single_logout_service_url)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns whether the request contains a single logout response for Service
|
66
|
+
# Provider initiated logout request. Returns true if the request contains a
|
67
|
+
# SAMLResponse query parameter and if the request's base_url and path match
|
68
|
+
# the single logout service url setting (single_logout_service_url),
|
69
|
+
# otherwise returns false.
|
70
|
+
#
|
71
|
+
# @return [Bool]
|
72
|
+
#
|
73
|
+
def logout_response?
|
74
|
+
request.params['SAMLResponse'].present? and "#{request.base_url}#{request.path}".eql?(@saml_settings.single_logout_service_url)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the RelayState in the header of the request or its query
|
78
|
+
# parameters.
|
79
|
+
#
|
80
|
+
# @return [String]
|
81
|
+
#
|
82
|
+
def relay_state_url
|
83
|
+
request.get_header('rack.request.form_hash')['RelayState'] || request.params['RelayState']
|
84
|
+
end
|
85
|
+
|
86
|
+
# A single sign-on response for the SAMLResponse in the request's header.
|
87
|
+
# This is the response sent by the ID Provider for Service Provider
|
88
|
+
# initiated single sign-on requests.
|
89
|
+
#
|
90
|
+
# @param auth_request_id [String] If provided, check that the inResponseTo
|
91
|
+
# in the response matches the uuid of the sign-on request that
|
92
|
+
# initiated the response.
|
93
|
+
# @param skip_conditions [Bool] Skip the conditions validation.
|
94
|
+
# @param allowed_clock_drift [Float] The allowed clock drift when checking
|
95
|
+
# time stamps.
|
96
|
+
# @param skip_subject_confirmation [Bool] Skip the subject confirmation
|
97
|
+
# validation.
|
98
|
+
# @param skip_recipient_check [Bool] Skip the recipient validation of the
|
99
|
+
# subject confirmation element.
|
100
|
+
# @param skip_audience [Bool] Skip the audience validation.
|
101
|
+
#
|
102
|
+
# @return [OneLogin::RubySaml::Response] A single sign-on response for a
|
103
|
+
# Service Provideer initiated single sign-on request.
|
104
|
+
#
|
105
|
+
def saml_auth_response (auth_request_id: request.session[:auth_request_id], skip_conditions: false, allowed_clock_drift: nil, skip_subject_confirmation: false, skip_recipient_check: false, skip_audience: false)
|
106
|
+
response = OneLogin::RubySaml::Response.new(
|
107
|
+
saml_response,
|
108
|
+
{ :settings => @saml_settings,
|
109
|
+
:matches_request_id => auth_request_id,
|
110
|
+
:skip_conditions => skip_conditions,
|
111
|
+
:allowed_clock_drift => allowed_clock_drift,
|
112
|
+
:skip_subject_confirmation => skip_subject_confirmation,
|
113
|
+
:skip_recipient_check => skip_recipient_check,
|
114
|
+
:skip_audience => skip_audience })
|
115
|
+
|
116
|
+
# the auth request's ID is no longer needed
|
117
|
+
request.session.delete(:auth_request_id)
|
118
|
+
|
119
|
+
response
|
120
|
+
end
|
121
|
+
|
122
|
+
# A single logout request for the SAMLRequest in the request's query
|
123
|
+
# parameters. This is the request sent by the ID Provider for ID Provider
|
124
|
+
# initiated single logout requests.
|
125
|
+
#
|
126
|
+
# @param allowed_clock_drift [Float] The allowed clock drift when checking
|
127
|
+
# time stamps.
|
128
|
+
# @param relax_signature_validation [Bool] If true and there's no ID
|
129
|
+
# Provider certs in the settings then ignore the signature validation
|
130
|
+
# on the request.
|
131
|
+
#
|
132
|
+
# @return [OneLogin::RubySaml::Logoutresponse] A single logout response for
|
133
|
+
# a Service Provideer initiated single logout request.
|
134
|
+
#
|
135
|
+
def saml_logout_request (allowed_clock_drift: nil, relax_signature_validation: false)
|
136
|
+
OneLogin::RubySaml::SloLogoutrequest.new(
|
137
|
+
request.params['SAMLRequest'],
|
138
|
+
{ :settings => @saml_settings,
|
139
|
+
:allowed_clock_drift => allowed_clock_drift,
|
140
|
+
:relax_signature_validation => relax_signature_validation })
|
141
|
+
end
|
142
|
+
|
143
|
+
# A single logout response for the SAMLResponse in the request's query
|
144
|
+
# parameters. This is the response sent by the ID Provider for Service
|
145
|
+
# Provider initiated single logout requests.
|
146
|
+
#
|
147
|
+
# @param logout_request_id [String] If provided, check that the inResponseTo
|
148
|
+
# in the response matches the uuid of the logout request that
|
149
|
+
# initiated the response.
|
150
|
+
# @param relax_signature_validation [Bool] If true and there's no ID
|
151
|
+
# Provider certs in the settings then ignore the signature validation
|
152
|
+
# on the response.
|
153
|
+
#
|
154
|
+
# @return [OneLogin::RubySaml::Logoutresponse] A single logout response for
|
155
|
+
# a Service Provideer initiated single logout request.
|
156
|
+
#
|
157
|
+
def saml_logout_response (logout_request_id: request.session[:logout_request_id], relax_signature_validation: false)
|
158
|
+
logout_response = OneLogin::RubySaml::Logoutresponse.new(
|
159
|
+
request.params['SAMLResponse'],
|
160
|
+
@saml_settings,
|
161
|
+
{ :get_params => request.params,
|
162
|
+
:matches_request_id => logout_request_id,
|
163
|
+
:relax_signature_validation => relax_signature_validation })
|
164
|
+
|
165
|
+
# the logout request's ID is no longer needed
|
166
|
+
request.session.delete(:logout_request_id)
|
167
|
+
|
168
|
+
logout_response
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns a single logout reponse URL for the settings provided. Used for ID
|
172
|
+
# Provider initiated log outs.
|
173
|
+
#
|
174
|
+
# @param request_id [String] The ID of the LogoutRequest sent by this SP to
|
175
|
+
# the IdP. That ID will be placed as the InResponseTo in the logout
|
176
|
+
# response.
|
177
|
+
# @param logout_message [String] The message to be placed as StatusMessage
|
178
|
+
# in the logout response.
|
179
|
+
# @param params [Hash] Extra query parameters to be added to the URL (e.g.
|
180
|
+
# RelayState).
|
181
|
+
# @param logout_status_code [String] The StatusCode to be placed as
|
182
|
+
# StatusMessage in the logout response.
|
183
|
+
#
|
184
|
+
# @return [String]
|
185
|
+
#
|
186
|
+
def slo_response_url (request_id: nil, logout_message: nil, params: {}, logout_status_code: nil)
|
187
|
+
OneLogin::RubySaml::SloLogoutresponse.new.create(
|
188
|
+
@saml_settings,
|
189
|
+
request_id,
|
190
|
+
logout_message,
|
191
|
+
params,
|
192
|
+
logout_status_code)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns a single logout request URL for the settings provided if an ID
|
196
|
+
# Provider single logout target URL is present in the settings
|
197
|
+
# (idp_slo_service_url), otherwise returns nil. Used for Service Provider
|
198
|
+
# initiated log outs.
|
199
|
+
#
|
200
|
+
# @param params [Hash] Extra query parameters to be added to the URL (e.g.
|
201
|
+
# RelayState).
|
202
|
+
#
|
203
|
+
# @return [String|nil]
|
204
|
+
#
|
205
|
+
def slo_url (params = {})
|
206
|
+
logout_request = OneLogin::RubySaml::Logoutrequest.new
|
207
|
+
|
208
|
+
if @saml_settings.idp_slo_service_url.present?
|
209
|
+
# store the logout request's uuid to validate it in the response
|
210
|
+
request.session[:logout_request_id] = logout_request.uuid
|
211
|
+
|
212
|
+
# return nil if no single logout url is set
|
213
|
+
logout_request.create(@saml_settings, params)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Returns a single sign-on authentication request URL for the settings
|
218
|
+
# provided. Used for Service Provider initiated sign-ins.
|
219
|
+
#
|
220
|
+
# @param params [Hash] Extra query parameters to be added to the URL (e.g.
|
221
|
+
# RelayState).
|
222
|
+
#
|
223
|
+
# @return [String]
|
224
|
+
#
|
225
|
+
def sso_url (params = {})
|
226
|
+
auth_request = OneLogin::RubySaml::Authrequest.new
|
227
|
+
|
228
|
+
# store the auth request's uuid to validate it in the response
|
229
|
+
request.session[:auth_request_id] = auth_request.uuid
|
230
|
+
|
231
|
+
auth_request.create(@saml_settings, params)
|
232
|
+
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def saml_response
|
237
|
+
request.get_header('rack.request.form_hash').try(:[], 'SAMLResponse')
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'rack_entra_id_auth/entra_id_request'
|
2
|
+
|
3
|
+
module RackEntraIdAuth
|
4
|
+
class Middleware
|
5
|
+
def initialize (app)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call (env)
|
10
|
+
request = Rack::Request.new(env)
|
11
|
+
entra_id_request = EntraIdRequest.new(request)
|
12
|
+
|
13
|
+
# SP initiated single sign-on request
|
14
|
+
if entra_id_request.login?
|
15
|
+
log(env, 'Redirecting login request to Entra ID single sign-on URL…')
|
16
|
+
|
17
|
+
sso_url = entra_id_request.sso_url(
|
18
|
+
{ :RelayState => request.params['relay_state'] ||
|
19
|
+
RackEntraIdAuth.config.login_relay_state_url ||
|
20
|
+
entra_id_request.base_url })
|
21
|
+
|
22
|
+
return found_redirect_response(
|
23
|
+
sso_url,
|
24
|
+
'Redirecting login request to Entra ID single sign-on URL')
|
25
|
+
end
|
26
|
+
|
27
|
+
# SP initiated logout/single logout request
|
28
|
+
if entra_id_request.logout?
|
29
|
+
log(env, 'Destroying session…')
|
30
|
+
|
31
|
+
# destroy session in case single logout fails
|
32
|
+
destroy_session()
|
33
|
+
|
34
|
+
relay_state_url = request.params['relay_state'] ||
|
35
|
+
RackEntraIdAuth.config.logout_relay_state_url ||
|
36
|
+
entra_id_request.base_url
|
37
|
+
|
38
|
+
slo_url = entra_id_request.slo_url({ :RelayState => relay_state_url })
|
39
|
+
|
40
|
+
if request.params['skip_single_logout'].blank? and
|
41
|
+
!RackEntraIdAuth.config.skip_single_logout and
|
42
|
+
slo_url.present?
|
43
|
+
|
44
|
+
log(env, 'Redirecting logout request to Entra ID single logout URL…')
|
45
|
+
|
46
|
+
return found_redirect_response(
|
47
|
+
slo_url,
|
48
|
+
'Redirecting logout request to Entra ID single logout URL')
|
49
|
+
end
|
50
|
+
|
51
|
+
log(env, 'Skipping single logout because of skip_single_logout query parameter…') if request.params['skip_single_logout'].present?
|
52
|
+
log(env, 'Skipping single logout because of skip_single_logout configuration setting…') if RackEntraIdAuth.config.skip_single_logout
|
53
|
+
log(env, 'Skipping single logout because no Entra ID single logout URL was found…') if slo_url.blank?
|
54
|
+
|
55
|
+
log(env, 'Redirecting to relay state URL…')
|
56
|
+
|
57
|
+
return found_redirect_response(relay_state_url)
|
58
|
+
end
|
59
|
+
|
60
|
+
# SP initiatied single sign-on response
|
61
|
+
if entra_id_request.login_response?
|
62
|
+
log(env, 'Received single login response…')
|
63
|
+
|
64
|
+
auth_response = entra_id_request.saml_auth_response()
|
65
|
+
|
66
|
+
if !auth_response.is_valid?
|
67
|
+
log(env, "Invalid single login reponse from Entra ID: #{auth_response.errors.first}")
|
68
|
+
|
69
|
+
return internal_server_error_response("Invalid login reponse from Entra ID: #{auth_response.errors.first}")
|
70
|
+
end
|
71
|
+
|
72
|
+
if !auth_response.success?
|
73
|
+
log(env, 'Unsuccessful single single reponse from Entra ID.')
|
74
|
+
|
75
|
+
return internal_server_error_response('Unsuccessful login reponse from Entra ID.')
|
76
|
+
end
|
77
|
+
|
78
|
+
log(env, 'Initializing session and redirecting to relay state URL…')
|
79
|
+
|
80
|
+
# initialize the session with the response's SAML attributes
|
81
|
+
request.session[RackEntraIdAuth.config.session_key] = RackEntraIdAuth.config.session_value_proc.call(auth_response.attributes.all)
|
82
|
+
|
83
|
+
return found_redirect_response(
|
84
|
+
entra_id_request.relay_state_url,
|
85
|
+
'Received single login response, redirecting to relay state URL')
|
86
|
+
end
|
87
|
+
|
88
|
+
# IdP initiatied single logout request
|
89
|
+
if entra_id_request.logout_request? and !RackEntraIdAuth.config.skip_single_logout
|
90
|
+
log(env, 'Received single logout request…')
|
91
|
+
|
92
|
+
logout_request = entra_id_request.saml_logout_request()
|
93
|
+
|
94
|
+
if !logout_request.is_valid?
|
95
|
+
log(env, "Invalid single logout request from Entra ID: #{logout_request.errors.first}")
|
96
|
+
|
97
|
+
return internal_server_error_response("Invalid logout request from Entra ID: #{logout_request.errors.first}")
|
98
|
+
end
|
99
|
+
|
100
|
+
log(env, 'Destroying session and sending logout response to Entra ID…')
|
101
|
+
|
102
|
+
# destroy the session
|
103
|
+
destroy_session()
|
104
|
+
|
105
|
+
response_url = entra_id_request.slo_response_url(
|
106
|
+
request_id: logout_request.id,
|
107
|
+
logout_message: nil,
|
108
|
+
params: {
|
109
|
+
:RelayState => entra_id_request.relay_state_url
|
110
|
+
},
|
111
|
+
logout_status_code: nil)
|
112
|
+
|
113
|
+
return found_redirect_response(
|
114
|
+
response_url,
|
115
|
+
'Received single logout request, redirecting to Entra ID')
|
116
|
+
end
|
117
|
+
|
118
|
+
# SP initiated single logout response
|
119
|
+
if entra_id_request.logout_response?
|
120
|
+
log(env, 'Received single logout response…')
|
121
|
+
|
122
|
+
logout_response = entra_id_request.saml_logout_response()
|
123
|
+
|
124
|
+
if !logout_response.validate
|
125
|
+
log(env, "Invalid single logout reponse from Entra ID: #{logout_response.errors.first}")
|
126
|
+
|
127
|
+
return internal_server_error_response("Invalid logout reponse from Entra ID: #{logout_response.errors.first}")
|
128
|
+
end
|
129
|
+
|
130
|
+
if !logout_response.success?
|
131
|
+
log(env, 'Unsuccessful single logout reponse from Entra ID.')
|
132
|
+
|
133
|
+
return internal_server_error_response('Unsuccessful logout reponse from Entra ID.')
|
134
|
+
end
|
135
|
+
|
136
|
+
log(env, 'Destroying session and redirecting to relay state URL…')
|
137
|
+
|
138
|
+
# session should already be destroyed from SP initiated logout/single
|
139
|
+
# logout request, but just to be safe…
|
140
|
+
destroy_session()
|
141
|
+
|
142
|
+
return found_redirect_response(
|
143
|
+
entra_id_request.relay_state_url,
|
144
|
+
'Received single logout response, redirecting to relay state URL')
|
145
|
+
end
|
146
|
+
|
147
|
+
response = @app.call(env)
|
148
|
+
|
149
|
+
# Authenticate 401s
|
150
|
+
if response[0] == 401
|
151
|
+
log(env, 'Intercepted 401 Unauthorized response, redirecting to Entra ID single sign-on URL…')
|
152
|
+
|
153
|
+
return found_redirect_response(
|
154
|
+
entra_id_request.sso_url(:RelayState => request.url),
|
155
|
+
'Intercepted 401 Unauthorized response, redirecting to Entra ID single sign-on URL')
|
156
|
+
end
|
157
|
+
|
158
|
+
response
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
|
163
|
+
def destroy_session ()
|
164
|
+
request.session.send(request.session.respond_to?(:destroy) ? :destroy : :clear)
|
165
|
+
end
|
166
|
+
|
167
|
+
def found_redirect_response (url, message = 'Redirecting to URL')
|
168
|
+
[ 302,
|
169
|
+
{ 'location' => url,
|
170
|
+
'content-type' => 'text/plain' },
|
171
|
+
[ "#{message}: #{url}" ] ]
|
172
|
+
end
|
173
|
+
|
174
|
+
def internal_server_error_response (content = 'Internal server error')
|
175
|
+
[ 500,
|
176
|
+
{ 'content-type' => 'text/html',
|
177
|
+
'content-length' => content.length },
|
178
|
+
[ content ] ]
|
179
|
+
end
|
180
|
+
|
181
|
+
def log (env, message, level = :info)
|
182
|
+
env['rack.logger'] ||= Rails.logger if defined?(Rails.logger)
|
183
|
+
message = "rack_entra_id_auth: #{message}"
|
184
|
+
|
185
|
+
if env['rack.logger']
|
186
|
+
env['rack.logger'].send(level, message)
|
187
|
+
else
|
188
|
+
env['rack.errors'].write(message.concat("\n"))
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
require 'rack_entra_id_auth/entra_id_request'
|
4
|
+
|
5
|
+
module RackEntraIdAuth
|
6
|
+
class MockMiddleware
|
7
|
+
def initialize (app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call (env)
|
12
|
+
request = Rack::Request.new(env)
|
13
|
+
entra_id_request = EntraIdRequest.new(request)
|
14
|
+
|
15
|
+
# mock a login page
|
16
|
+
if entra_id_request.login? and request.request_method.eql?('GET')
|
17
|
+
log(env, 'Rendering mock login page…')
|
18
|
+
|
19
|
+
return [ 200,
|
20
|
+
{ 'Content-Type' => 'text/html' },
|
21
|
+
[ login_page(request.url) ] ]
|
22
|
+
end
|
23
|
+
|
24
|
+
# mock a login request
|
25
|
+
if entra_id_request.login? and request.request_method.eql?('POST')
|
26
|
+
log(env, 'Initializing session and redirecting to relay state URL…')
|
27
|
+
|
28
|
+
attributes = RackEntraIdAuth.config.mock_attributes[request.params['username']] || {}
|
29
|
+
redirect_url = request.params['relay_state'] ||
|
30
|
+
request.params['RelayState'] ||
|
31
|
+
RackEntraIdAuth.config.login_relay_state_url ||
|
32
|
+
entra_id_request.base_url
|
33
|
+
|
34
|
+
request.session[RackEntraIdAuth.config.session_key] = RackEntraIdAuth.config.session_value_proc.call(attributes)
|
35
|
+
|
36
|
+
return found_redirect_response(
|
37
|
+
redirect_url,
|
38
|
+
'Initializing session and redirecting to relay state URL')
|
39
|
+
end
|
40
|
+
|
41
|
+
# mock a logout request
|
42
|
+
if entra_id_request.logout?
|
43
|
+
log(env, 'Destroying session and redirecting to relay state URL…')
|
44
|
+
|
45
|
+
redirect_url = request.params['relay_state'] ||
|
46
|
+
request.params['RelayState'] ||
|
47
|
+
RackEntraIdAuth.config.logout_relay_state_url ||
|
48
|
+
entra_id_request.base_url
|
49
|
+
|
50
|
+
request.session.send(request.session.respond_to?(:destroy) ? :destroy : :clear)
|
51
|
+
|
52
|
+
return found_redirect_response(
|
53
|
+
redirect_url,
|
54
|
+
'Destroying session and redirecting to relay state URL')
|
55
|
+
end
|
56
|
+
|
57
|
+
response = @app.call(env)
|
58
|
+
|
59
|
+
# Authenticate 401s
|
60
|
+
if response[0] == 401
|
61
|
+
log(env, 'Intercepted 401 Unauthorized response, redirecting to mock login URL…')
|
62
|
+
|
63
|
+
login_url = URI::HTTP.build(host: request.host,
|
64
|
+
port: request.port,
|
65
|
+
path: RackEntraIdAuth.config.login_path,
|
66
|
+
query: URI.encode_www_form({ :RelayState => request.url }))
|
67
|
+
|
68
|
+
return found_redirect_response(
|
69
|
+
login_url,
|
70
|
+
'Intercepted 401 Unauthorized response, redirecting to mock login URL')
|
71
|
+
end
|
72
|
+
|
73
|
+
response
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def found_redirect_response (url, message = 'Redirecting to URL')
|
79
|
+
[ 302,
|
80
|
+
{ 'location' => url,
|
81
|
+
'content-type' => 'text/plain' },
|
82
|
+
[ "#{message}: #{url}" ] ]
|
83
|
+
end
|
84
|
+
|
85
|
+
def log (env, message, level = :info)
|
86
|
+
env['rack.logger'] ||= Rails.logger if defined?(Rails.logger)
|
87
|
+
message = "rack_entra_id_auth: #{message}"
|
88
|
+
|
89
|
+
if env['rack.logger']
|
90
|
+
env['rack.logger'].send(level, message)
|
91
|
+
else
|
92
|
+
env['rack.errors'].write(message.concat("\n"))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def login_page (action)
|
97
|
+
options = RackEntraIdAuth.config.mock_attributes.keys.map { |key| %Q~<option value="#{key}">#{key}</option>~ } .join
|
98
|
+
|
99
|
+
<<-EOS
|
100
|
+
<!DOCTYPE html>
|
101
|
+
<html>
|
102
|
+
<head>
|
103
|
+
<meta charset="utf-8">
|
104
|
+
<title>Mock Middleware Login</title>
|
105
|
+
</head>
|
106
|
+
|
107
|
+
<body>
|
108
|
+
<form action="#{action}" method="post">
|
109
|
+
<label for="username">Username</label>
|
110
|
+
|
111
|
+
<select id="username" name="username">
|
112
|
+
<option label="No User" value=""></option>
|
113
|
+
#{options}
|
114
|
+
</select>
|
115
|
+
|
116
|
+
<input type="submit" value="Login">
|
117
|
+
</form>
|
118
|
+
</body>
|
119
|
+
</html>
|
120
|
+
EOS
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module RackEntraIdAuth
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
config.rack_entra_id_auth = RackEntraIdAuth.config
|
6
|
+
|
7
|
+
initializer 'Add RackEntraIdAuth Middleware' do |app|
|
8
|
+
if config.rack_entra_id_auth.mock_server
|
9
|
+
require 'rack_entra_id_auth/mock_middleware'
|
10
|
+
|
11
|
+
app.middleware.use MockMiddleware
|
12
|
+
else
|
13
|
+
require 'rack_entra_id_auth/middleware'
|
14
|
+
|
15
|
+
app.middleware.use Middleware
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rack_entra_id_auth/configuration'
|
2
|
+
|
3
|
+
module RackEntraIdAuth
|
4
|
+
def self.configure
|
5
|
+
yield config
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.config
|
9
|
+
@config ||= Configuration.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# done here so the RackEntraIdAuth.config method can be used in the Railtie
|
14
|
+
require 'rack_entra_id_auth/railtie' if defined?(Rails::Railtie)
|
metadata
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rack_entra_id_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Susco
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-08-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '7.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ruby-saml
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.10'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.10'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.16'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.16'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '13.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '13.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.21'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.21'
|
97
|
+
description: Rails aware Rack middleware for Entra ID authentication.
|
98
|
+
email:
|
99
|
+
- dsusco@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- MIT-LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- lib/generators/rack_entra_id_auth/initializer_generator.rb
|
108
|
+
- lib/generators/rack_entra_id_auth/routes_generator.rb
|
109
|
+
- lib/generators/rack_entra_id_auth/templates/config_initializer.rb
|
110
|
+
- lib/rack_entra_id_auth.rb
|
111
|
+
- lib/rack_entra_id_auth/configuration.rb
|
112
|
+
- lib/rack_entra_id_auth/entra_id_request.rb
|
113
|
+
- lib/rack_entra_id_auth/middleware.rb
|
114
|
+
- lib/rack_entra_id_auth/mock_middleware.rb
|
115
|
+
- lib/rack_entra_id_auth/railtie.rb
|
116
|
+
- lib/rack_entra_id_auth/version.rb
|
117
|
+
homepage: https://github.com/dsusco/rack_entra_id_auth
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
metadata:
|
121
|
+
bug_tracker_uri: https://github.com/dsusco/rack_entra_id_auth/issues
|
122
|
+
changelog_uri: https://github.com/dsusco/rack_entra_id_auth/releases/tag/v1.0.0
|
123
|
+
homepage_uri: https://github.com/dsusco/rack_entra_id_auth
|
124
|
+
source_code_uri: https://github.com/dsusco/rack_entra_id_auth
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 3.0.0
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubygems_version: 3.5.11
|
141
|
+
signing_key:
|
142
|
+
specification_version: 4
|
143
|
+
summary: Rails aware Rack middleware for Entra ID authentication.
|
144
|
+
test_files: []
|