summaryrefslogtreecommitdiff
path: root/bin/idp
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-03-05 11:43:07 -0700
committermo khan <mo@mokhan.ca>2025-03-05 11:43:07 -0700
commit20e152182f7137ae2c7f512d0cab1b3c846a4677 (patch)
tree9c7a0ca1e52abc1d9fd2a77ec0c3b3b6166c4dd0 /bin/idp
parent502228f90f6e3e7b03d2c3165a9b8b8f00e29dce (diff)
refactor: extract scheme and provide the appropriate nameid for saml transaction
Diffstat (limited to 'bin/idp')
-rwxr-xr-xbin/idp79
1 files changed, 47 insertions, 32 deletions
diff --git a/bin/idp b/bin/idp
index d568c605..026655c1 100755
--- a/bin/idp
+++ b/bin/idp
@@ -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