# stdlib require "fileutils" # external libraries require "openid" require "openid/extension" require "openid/extensions/sreg" require "openid/store/filesystem" require "openid/util" require "rack/request" require "rack/utils" module Rots class ServerApp attr_accessor :request, :openid_request, :response, :openid_response, :server def initialize(config, server_options) @server_options = server_options @sreg_fields = config["sreg"] end def call(env) on_openid_request(env) do if !is_checkid_request? @openid_response = @server.handle_request(@openid_request) reply_consumer elsif is_checkid_immediate? process_immediate_checkid_request else process_checkid_request end end end protected def on_openid_request(env) create_wrappers(env) if @openid_request.nil? [ 200, {Rack::CONTENT_TYPE => "text/html"}, ["

ROTS => This is an OpenID endpoint

"], ] else yield end end def create_wrappers(env) @request = Rack::Request.new(env) @server = OpenID::Server::Server.new(storage, op_endpoint) @openid_request = @server.decode_request(@request.params) @openid_sreg_request = OpenID::SReg::Request.from_openid_request(@openid_request) unless @openid_request.nil? end def is_checkid_request? @openid_request.is_a?(OpenID::Server::CheckIDRequest) end def is_checkid_immediate? @openid_request && @openid_request.immediate end def process_immediate_checkid_request if checkid_immediate_is_valid? return_successful_openid_response else return_setup_needed_openid_response end end def process_checkid_request if checkid_request_is_valid? return_successful_openid_response else return_cancel_openid_response end end def checkid_request_is_valid? @request.params["openid.success"] == "true" end def checkid_immediate_is_valid? @request.params["openid.success"] == "true" end def return_successful_openid_response @openid_response = @openid_request.answer(true) process_sreg_extension # TODO: Add support for SREG extension @server.signatory.sign(@openid_response) if @openid_response.needs_signing reply_consumer end def process_sreg_extension return if @openid_sreg_request.nil? response = OpenID::SReg::Response.extract_response(@openid_sreg_request, @sreg_fields) @openid_response.add_extension(response) end def return_cancel_openid_response redirect(@openid_request.cancel_url) end def return_setup_needed_openid_response setup_needed_args = @request.params.merge("openid.mode" => "setup_needed", "user_setup_url" => "") url = OpenID::Util.append_args(@openid_request.return_to, setup_needed_args) redirect(url) end def reply_consumer web_response = @server.encode_response(@openid_response) case web_response.code when OpenID::Server::HTTP_OK success(web_response.body) when OpenID::Server::HTTP_REDIRECT redirect(web_response.headers["location"]) else bad_request end end def redirect(uri) [ 303, { Rack::CONTENT_LENGTH => "0", Rack::CONTENT_TYPE => "text/plain", "Location" => uri, }, [], ] end def bad_request [ 400, {Rack::CONTENT_TYPE => "text/plain", Rack::CONTENT_LENGTH => "0"}, [], ] end def storage # create the folder if it doesn't exist FileUtils.mkdir_p(@server_options[:storage]) unless File.exist?(@server_options[:storage]) OpenID::Store::Filesystem.new(@server_options[:storage]) end def success(text = "") Rack::Response.new(text).finish end def op_endpoint if @request.url =~ /(.*\?openid.success=true)/ $1 elsif @request.url =~ /([^?]*)/ $1 end end end end