diff options
| -rwxr-xr-x | bin/idp | 123 |
1 files changed, 108 insertions, 15 deletions
@@ -28,6 +28,10 @@ $port = ENV.fetch("PORT", 8282).to_i $host = ENV.fetch("HOST", "localhost:#{$port}") module HTTPHelpers + def logged_in?(request) + request.session[:user_id] + end + def default_headers { 'X-Powered-By' => 'IdP' @@ -41,6 +45,10 @@ module HTTPHelpers def http_ok(headers = {}, body = nil) [200, default_headers.merge(headers), [body]] end + + def http_redirect_to(location) + [302, { 'Location' => location }, []] + end end module Authn @@ -112,6 +120,57 @@ module Authn end end + class SessionsController + include ::HTTPHelpers + + def call(env) + request = Rack::Request.new(env) + case request.request_method + when Rack::GET + case request.path + when '/sessions/new' + return get_login(request) + end + when Rack::POST + case request.path + when '/sessions' + if (user = User.find_by_credentials(request.params)) + request.session[:user_id] = user[:id] + return http_redirect_to('/') + else + return http_redirect_to("/sessions/new") + end + when '/sessions/delete' + request.session.delete(:user_id) + return http_redirect_to('/') + end + end + + http_not_found + end + + private + + def get_login(request) + template = <<~ERB + <!DOCTYPE html> + <html> + <head><title></title></head> + <body> + <form id="login-form" action="/sessions" method="post"> + <input type="input" placeholder="Username" id="username" name="username" value="" /> + <input type="password" placeholder="Password" id="password" name="password" value="" /> + <input type="submit" id="login-button" value="Login" /> + </form> + </body> + </html> + ERB + erb = ERB.new(template, trim_mode: '-') + html = erb.result(binding) + [200, { 'Content-Type' => "text/html" }, [html]] + end + end + class SAMLController include ::HTTPHelpers @@ -198,7 +257,7 @@ module Authn def saml_post_back(request, user) params = saml_params_from(request) saml_request = binding_for(request).deserialize(params) - request.session[:access_token] = user.create_access_token + request.session[:user_id] = user[:id] @builder = nil url, saml_params = saml_request.response_for( @@ -330,22 +389,25 @@ module Authz include ::HTTPHelpers def call(env) - path = env['PATH_INFO'] - case env['REQUEST_METHOD'] - when 'GET' - case path + request = Rack::Request.new(env) + + case request.request_method + when Rack::GET + case request.path_info when "/authorize" # RFC-6749 - return get_authorize(Rack::Request.new(env)) + if logged_in?(request) + return get_authorize(request) + else + http_redirect_to("/saml/") + end else return http_not_found end - when 'POST' - case path + when Rack::POST + case request.path_info when "/authorize" # RFC-6749 - return post_authorize(Rack::Request.new(env)) + return post_authorize(request) when "/token" # RFC-6749 - request = Rack::Request.new(env) - return [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ access_token: ::Authz::JWT.new(sub: SecureRandom.uuid, iat: Time.now.to_i).to_jwt, token_type: "Bearer", @@ -413,10 +475,17 @@ class IdentityProvider include ::HTTPHelpers def call(env) - path = env['PATH_INFO'] - case env['REQUEST_METHOD'] - when 'GET' - case path + request = Rack::Request.new(env) + + case request.request_method + when Rack::GET + case request.path + when '/' + if logged_in?(request) + return get_dashboard(request) + else + return http_redirect_to("/sessions/new") + end when '/.well-known/openid-configuration' return openid_metadata when '/.well-known/oauth-authorization-server' @@ -432,6 +501,26 @@ class IdentityProvider private + def get_dashboard(request) + template = <<~ERB + <!DOCTYPE html> + <html> + <head><title></title></head> + <body> + <h1>Dashboard</h1> + <pre><%= request.session[:access_token] %></pre> + + <form action="/sessions/delete" method="post"> + <input type="submit" value="logout" /> + </form> + </body> + </html> + ERB + erb = ERB.new(template, trim_mode: '-') + html = erb.result(binding) + [200, { 'Content-Type' => "text/html" }, [html]] + end + # GET /.well-known/oauth-authorization-server def oauth_metadata [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ @@ -534,6 +623,10 @@ if __FILE__ == $0 map "/saml" do run Authn::SAMLController.new($scheme, $host) end + + map "/sessions" do + run Authn::SessionsController.new + end run IdentityProvider.new end.to_app |
