diff options
| author | mo khan <mo@mokhan.ca> | 2025-03-05 11:43:07 -0700 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-03-05 11:43:07 -0700 |
| commit | 20e152182f7137ae2c7f512d0cab1b3c846a4677 (patch) | |
| tree | 9c7a0ca1e52abc1d9fd2a77ec0c3b3b6166c4dd0 /bin/idp | |
| parent | 502228f90f6e3e7b03d2c3165a9b8b8f00e29dce (diff) | |
refactor: extract scheme and provide the appropriate nameid for saml transaction
Diffstat (limited to 'bin/idp')
| -rwxr-xr-x | bin/idp | 79 |
1 files changed, 47 insertions, 32 deletions
@@ -13,18 +13,44 @@ gemfile do gem "webrick", "~> 1.0" end +$scheme = ENV.fetch('SCHEME', 'http') +$port = ENV.fetch('PORT', 8282).to_i +$host = ENV.fetch('HOST', "localhost:#{$port}") + +class JWT + attr_reader :claims + + def initialize(claims) + @claims = claims + end + + def to_jwt + [ + Base64.strict_encode64(JSON.generate({alg: "RS256", typ: "JWT"})), + Base64.strict_encode64(JSON.generate(claims)), + Base64.strict_encode64(JSON.generate({})), + ].join(".") + end +end + class User def initialize(attributes) @attributes = attributes end def name_id_for(name_id_format) - @attributes[:email] + if name_id_format == Saml::Kit::Namespaces::EMAIL_ADDRESS + @attributes[:email] + else + @attributes[:id] + end end def assertion_attributes_for(request) { - custom: 'custom attribute' + custom: 'custom attribute', + email: @attributes[:email], + access_token: JWT.new(sub: SecureRandom.uuid, iat: Time.now.to_i).to_jwt, } end end @@ -40,16 +66,12 @@ class OnDemandRegistry < Saml::Kit::DefaultRegistry end Saml::Kit.configure do |x| - x.entity_id = "http://localhost:8282/metadata.xml" + x.entity_id = "#{$scheme}://#{$host}/metadata.xml" x.registry = OnDemandRegistry.new x.logger = Logger.new("/dev/stderr") end class IdentityProvider - def initialize - @storage = {} - end - def call(env) path = env['PATH_INFO'] case env['REQUEST_METHOD'] @@ -63,7 +85,8 @@ class IdentityProvider return not_found when "/metadata.xml" return saml_metadata - when "/sessions/new" + when "/saml/new" + # TODO:: render a login page return saml_post_back(Rack::Request.new(env)) when "/oauth/authorize" # RFC-6749 return get_authorize(Rack::Request.new(env)) @@ -72,13 +95,13 @@ class IdentityProvider end when 'POST' case path - when "/sessions/new" + when "/saml/new" return saml_post_back(Rack::Request.new(env)) when "/oauth/authorize" # RFC-6749 return post_authorize(Rack::Request.new(env)) when "/oauth/token" # RFC-6749 return [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - access_token: to_jwt(sub: SecureRandom.uuid, iat: Time.now.to_i), + access_token: JWT.new(sub: SecureRandom.uuid, iat: Time.now.to_i).to_jwt, token_type: "Bearer", expires_in: 3600, refresh_token: SecureRandom.hex(32) @@ -94,14 +117,6 @@ class IdentityProvider private - def to_jwt(claims) - [ - Base64.strict_encode64(JSON.generate({alg: "RS256", typ: "JWT"})), - Base64.strict_encode64(JSON.generate(claims)), - Base64.strict_encode64(JSON.generate({})), - ].join(".") - end - # Download IDP Metadata # # GET /metadata.xml @@ -111,7 +126,7 @@ class IdentityProvider builder.organization_name = "Acme, Inc" builder.organization_url = "https://example.com" builder.build_identity_provider do |x| - x.add_single_sign_on_service("http://localhost:8282/sessions/new", binding: :http_post) + x.add_single_sign_on_service("#{$scheme}://#{$host}/saml/new", binding: :http_post) x.name_id_formats = [Saml::Kit::Namespaces::EMAIL_ADDRESS] x.attributes << :Username end @@ -123,9 +138,9 @@ class IdentityProvider # GET /.well-known/oauth-authorization-server def oauth_metadata [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - issuer: "http://localhost:8282/.well-known/oauth-authorization-server", - authorization_endpoint: "http://localhost:8282/oauth/authorize", - token_endpoint: "http://localhost:8282/oauth/token", + issuer: "#{$scheme}://#{$host}/.well-known/oauth-authorization-server", + authorization_endpoint: "#{$scheme}://#{$host}/oauth/authorize", + token_endpoint: "#{$scheme}://#{$host}/oauth/token", jwks_uri: "", # RFC-7517 registration_endpoint: "", # RFC-7591 scopes_supported: ["openid", "profile", "email"], @@ -138,10 +153,10 @@ class IdentityProvider ui_locales_supported: ["en-US"], op_policy_uri: "", op_tos_uri: "", - revocation_endpoint: "http://localhost:8282/oauth/revoke", # RFC-7009 + revocation_endpoint: "#{$scheme}://#{$host}/oauth/revoke", # RFC-7009 revocation_endpoint_auth_methods_supported: ["client_secret_basic"], revocation_endpoint_auth_signing_alg_values_supported: ["RS256"], - introspection_endpoint: "http://localhost:8282/oauth/introspect", # RFC-7662 + introspection_endpoint: "#{$scheme}://#{$host}/oauth/introspect", # RFC-7662 introspection_endpoint_auth_methods_supported: ["client_secret_basic"], introspection_endpoint_auth_signing_alg_values_supported: ["RS256"], code_challenge_methods_supported: [], # RFC-7636 @@ -196,10 +211,10 @@ class IdentityProvider # GET /.well-known/openid-configuration def openid_metadata [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - issuer: "http://localhost:8282/.well-known/oauth-authorization-server", - authorization_endpoint: "http://localhost:8282/oauth/authorize", - token_endpoint: "http://localhost:8282/oauth/token", - userinfo_endpoint: "http://localhost:8282/oidc/user/", + issuer: "#{$scheme}://#{$host}/.well-known/oauth-authorization-server", + authorization_endpoint: "#{$scheme}://#{$host}/oauth/authorize", + token_endpoint: "#{$scheme}://#{$host}/oauth/token", + userinfo_endpoint: "#{$scheme}://#{$host}/oidc/user/", jwks_uri: "", # RFC-7517 registration_endpoint: nil, scopes_supported: ["openid", "profile", "email"], @@ -254,7 +269,7 @@ class IdentityProvider saml_request = binding_for(request).deserialize(params) @builder = nil url, saml_params = saml_request.response_for( - User.new({ email: "example@example.com" }), + User.new({ id: SecureRandom.uuid, email: "example@example.com" }), binding: :http_post, relay_state: params[:RelayState] ) do |builder| @@ -270,7 +285,7 @@ class IdentityProvider <textarea readonly="readonly" disabled="disabled" cols=225 rows=6><%=- saml_request.to_xml(pretty: true) -%></textarea> <h2>Sending SAML Response (IdP -> SP)</h2> - <textarea readonly="readonly" disabled="disabled" cols=225 rows=30><%=- @builder.build.to_xml(pretty: true) -%></textarea> + <textarea readonly="readonly" disabled="disabled" cols=225 rows=40><%=- @builder.build.to_xml(pretty: true) -%></textarea> <form action="<%= url %>" method="post"> <%- saml_params.each do |(key, value)| -%> <input type="hidden" name="<%= key %>" value="<%= value %>" /> @@ -303,7 +318,7 @@ class IdentityProvider end def binding_for(request) - location = "http://localhost:8282/sessions/new" + location = "#{$scheme}://#{$host}/saml/new" if request.post? Saml::Kit::Bindings::HttpPost .new(location: location) @@ -320,5 +335,5 @@ if __FILE__ == $0 run IdentityProvider.new end.to_app - Rackup::Server.start(app: app, Port: ENV.fetch('PORT', 8282).to_i) + Rackup::Server.start(app: app, Port: $port) end |
