rots 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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��%��