rots 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,167 @@
1
+ # stdlib
2
+ require "fileutils"
3
+
4
+ # external libraries
5
+ require "openid"
6
+ require "openid/extension"
7
+ require "openid/extensions/sreg"
8
+ require "openid/store/filesystem"
9
+ require "openid/util"
10
+ require "rack/request"
11
+ require "rack/utils"
12
+
13
+ module Rots
14
+ class ServerApp
15
+ attr_accessor :request,
16
+ :openid_request,
17
+ :response,
18
+ :openid_response,
19
+ :server
20
+
21
+ def initialize(config, server_options)
22
+ @server_options = server_options
23
+ @sreg_fields = config["sreg"]
24
+ end
25
+
26
+ def call(env)
27
+ on_openid_request(env) do
28
+ if !is_checkid_request?
29
+ @openid_response = @server.handle_request(@openid_request)
30
+ reply_consumer
31
+ elsif is_checkid_immediate?
32
+ process_immediate_checkid_request
33
+ else
34
+ process_checkid_request
35
+ end
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def on_openid_request(env)
42
+ create_wrappers(env)
43
+ if @openid_request.nil?
44
+ [
45
+ 200,
46
+ {Rack::CONTENT_TYPE => "text/html"},
47
+ ["<html><body><h1>ROTS => This is an OpenID endpoint</h1></body></html>"],
48
+ ]
49
+ else
50
+ yield
51
+ end
52
+ end
53
+
54
+ def create_wrappers(env)
55
+ @request = Rack::Request.new(env)
56
+ @server = OpenID::Server::Server.new(storage, op_endpoint)
57
+ @openid_request = @server.decode_request(@request.params)
58
+ @openid_sreg_request = OpenID::SReg::Request.from_openid_request(@openid_request) unless @openid_request.nil?
59
+ end
60
+
61
+ def is_checkid_request?
62
+ @openid_request.is_a?(OpenID::Server::CheckIDRequest)
63
+ end
64
+
65
+ def is_checkid_immediate?
66
+ @openid_request && @openid_request.immediate
67
+ end
68
+
69
+ def process_immediate_checkid_request
70
+ if checkid_immediate_is_valid?
71
+ return_successful_openid_response
72
+ else
73
+ return_setup_needed_openid_response
74
+ end
75
+ end
76
+
77
+ def process_checkid_request
78
+ if checkid_request_is_valid?
79
+ return_successful_openid_response
80
+ else
81
+ return_cancel_openid_response
82
+ end
83
+ end
84
+
85
+ def checkid_request_is_valid?
86
+ @request.params["openid.success"] == "true"
87
+ end
88
+
89
+ def checkid_immediate_is_valid?
90
+ @request.params["openid.success"] == "true"
91
+ end
92
+
93
+ def return_successful_openid_response
94
+ @openid_response = @openid_request.answer(true)
95
+ process_sreg_extension
96
+ # TODO: Add support for SREG extension
97
+ @server.signatory.sign(@openid_response) if @openid_response.needs_signing
98
+ reply_consumer
99
+ end
100
+
101
+ def process_sreg_extension
102
+ return if @openid_sreg_request.nil?
103
+ response = OpenID::SReg::Response.extract_response(@openid_sreg_request, @sreg_fields)
104
+ @openid_response.add_extension(response)
105
+ end
106
+
107
+ def return_cancel_openid_response
108
+ redirect(@openid_request.cancel_url)
109
+ end
110
+
111
+ def return_setup_needed_openid_response
112
+ setup_needed_args = @request.params.merge("openid.mode" => "setup_needed", "user_setup_url" => "")
113
+ url = OpenID::Util.append_args(@openid_request.return_to, setup_needed_args)
114
+ redirect(url)
115
+ end
116
+
117
+ def reply_consumer
118
+ web_response = @server.encode_response(@openid_response)
119
+ case web_response.code
120
+ when OpenID::Server::HTTP_OK
121
+ success(web_response.body)
122
+ when OpenID::Server::HTTP_REDIRECT
123
+ redirect(web_response.headers["location"])
124
+ else
125
+ bad_request
126
+ end
127
+ end
128
+
129
+ def redirect(uri)
130
+ [
131
+ 303,
132
+ {
133
+ Rack::CONTENT_LENGTH => "0",
134
+ Rack::CONTENT_TYPE => "text/plain",
135
+ "Location" => uri,
136
+ },
137
+ [],
138
+ ]
139
+ end
140
+
141
+ def bad_request
142
+ [
143
+ 400,
144
+ {Rack::CONTENT_TYPE => "text/plain", Rack::CONTENT_LENGTH => "0"},
145
+ [],
146
+ ]
147
+ end
148
+
149
+ def storage
150
+ # create the folder if it doesn't exist
151
+ FileUtils.mkdir_p(@server_options[:storage]) unless File.exist?(@server_options[:storage])
152
+ OpenID::Store::Filesystem.new(@server_options[:storage])
153
+ end
154
+
155
+ def success(text = "")
156
+ Rack::Response.new(text).finish
157
+ end
158
+
159
+ def op_endpoint
160
+ if @request.url =~ /(.*\?openid.success=true)/
161
+ $1
162
+ elsif @request.url =~ /([^?]*)/
163
+ $1
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,21 @@
1
+ module Rots
2
+ module Test
3
+ module RackTestHelpers
4
+ def mock_openid_request(app, *args)
5
+ env = Rack::MockRequest.env_for(*args)
6
+ @response = Rack::MockResponse.new(*app.call(env))
7
+ end
8
+
9
+ def follow_openid_redirect!(app)
10
+ assert(@response)
11
+ assert_equal(303, @response.status)
12
+
13
+ env = Rack::MockRequest.env_for(@response.headers["Location"])
14
+ _status, headers, _body = Rots::Mocks::RotsServer.new.call(env)
15
+
16
+ uri = URI(headers["Location"])
17
+ mock_openid_request(app, "#{uri.path}?#{uri.query}")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,78 @@
1
+ require "rack/utils"
2
+
3
+ module Rots
4
+ module Test
5
+ module RequestHelper
6
+ def openid_request(openid_request_uri)
7
+ openid_response = Net::HTTP.get_response(URI.parse(openid_request_uri))
8
+ openid_response_uri = URI(openid_response["Location"])
9
+ openid_response_qs = Rack::Utils.parse_query(openid_response_uri.query)
10
+
11
+ {
12
+ url: openid_response_uri.to_s,
13
+ query_params: openid_response_qs,
14
+ }
15
+ end
16
+
17
+ def checkid_setup(request, params = {}, with_associate = true)
18
+ assoc_handle = make_association(request) if with_associate
19
+ send_checkid(request, :setup, params, assoc_handle)
20
+ end
21
+
22
+ def checkid_immediate(request, params = {}, with_associate = true)
23
+ assoc_handle = make_association(request) if with_associate
24
+ send_checkid(request, :immediate, params, assoc_handle)
25
+ end
26
+
27
+ def openid_params(response)
28
+ uri = URI(response.headers["Location"])
29
+ Rack::Utils.parse_query(uri.query)
30
+ end
31
+
32
+ protected
33
+
34
+ def send_checkid(request, mode, params = {}, assoc_handle = nil)
35
+ params = send(:"checkid_#{mode}_params", params)
36
+ params.merge("openid.assoc_handle" => assoc_handle) if assoc_handle
37
+ qs = "/?" + Rack::Utils.build_query(params)
38
+ request.get(qs)
39
+ end
40
+
41
+ def make_association(request)
42
+ associate_qs = Rack::Utils.build_query(associate_params)
43
+ response = request.post("/", input: associate_qs)
44
+ parse_assoc_handle_from(response)
45
+ end
46
+
47
+ def parse_assoc_handle_from(response)
48
+ response.body.split("\n")[0].match(/^assoc_handle:(.*)$/).captures[0]
49
+ end
50
+
51
+ def checkid_setup_params(params = {})
52
+ {
53
+ "openid.ns" => "http://specs.openid.net/auth/2.0",
54
+ "openid.mode" => "checkid_setup",
55
+ "openid.claimed_id" => "john.doe",
56
+ "openid.identity" => "john.doe",
57
+ "openid.return_to" => "http://www.google.com",
58
+ # need to specify the openid_handle by hand
59
+ }.merge!(params)
60
+ end
61
+
62
+ def checkid_immediate_params(params = {})
63
+ checkid_setup_params({"openid.mode" => "checkid_immediate"}.merge!(params))
64
+ end
65
+
66
+ def associate_params
67
+ {
68
+ "openid.ns" => "http://specs.openid.net/auth/2.0",
69
+ "openid.mode" => "associate",
70
+ "openid.session_type" => "DH-SHA1",
71
+ "openid.assoc_type" => "HMAC-SHA1",
72
+ "openid.dh_consumer_public" =>
73
+ "U672/RsDUNxAFFAXA+ShVh5LMD2CRdsoqdqhDCPUzfCNy2f44uTWuid/MZuGfJmiVA7QmxqM3GSb8EVq3SGK8eGEwwyzUtatqHidx72rfwAav5AUrZTnwSPQJyiCFrKNGmNhXdRJzcfzSkgaC3hVz2kpADzEevIExG6agns1sYY=",
74
+ }
75
+ end
76
+ end
77
+ end
78
+ end
data/lib/rots/test.rb ADDED
@@ -0,0 +1,2 @@
1
+ require_relative "test/rack_test_helpers"
2
+ require_relative "test/request_helper"
@@ -0,0 +1,5 @@
1
+ module Rots
2
+ module Version
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
data/lib/rots.rb ADDED
@@ -0,0 +1,27 @@
1
+ # stdlib in Ruby < 3, gem after
2
+ require "net/http"
3
+
4
+ # External Libraries
5
+ require "date"
6
+ require "openssl"
7
+ require "optparse"
8
+ require "rack"
9
+ require "rackup"
10
+ require "openid" # ruby-openid2
11
+ require "stringio"
12
+ require "webrick"
13
+ require "yaml"
14
+ require "psych"
15
+
16
+ # This library
17
+ require_relative "rots/version"
18
+ require_relative "rots/server_app"
19
+ require_relative "rots/identity_page_app"
20
+
21
+ # Namespace for this gem
22
+ module Rots
23
+ end
24
+
25
+ Rots::Version.class_eval do
26
+ extend VersionGem::Basic
27
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,5 @@
1
+ ������%P{ޱ��3܅`�/\���z��%͐z��4r��-��`�Z�a�nՑm,���c�Z~mC:ϚB�u��m3�ȟ� ���f�, O��
2
+ ������>��r�ُ;K�
3
+ �v5�=�תEj��w'U}����f��*7�*�䰍 ����5���*��e�m~6��<V��"�0 (�'��b���D9,{�4�eV � �qd���9%@2buwˤ�F��L<�!~���KG����ض�l��N�u��i�?�K_��
4
+ }P? K�F��~[��tz��֫)K����Jz�uƪ��Y-]�Lݛ������M`��9�a*(�2���3Kw�6\q�#-��*&� �&��&��
5
+ #�fy��+?&~'�$FL] �.~��5��%��