(Not documented)
# File bin/local-openid, line 167
167: def add_pape(oidreq, oidresp)
168: papereq = OpenID::PAPE::Request.from_openid_request(oidreq) or return
169: paperesp = OpenID::PAPE::Response.new(papereq.preferred_auth_policies,
170: papereq.max_auth_age)
171: # since this implementation requires shell/filesystem access to the
172: # OpenID server to authenticate, we can say we're at the highest
173: # auth level possible...
174: paperesp.add_policy_uri(OpenID::PAPE::AUTH_MULTI_FACTOR_PHYSICAL)
175: paperesp.auth_time = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
176: paperesp.nist_auth_level = 4
177: oidresp.add_extension(paperesp)
178: end
support the simple registration extension if possible, allow per-site overrides of various data points
# File bin/local-openid, line 154
154: def add_sreg(oidreq, oidresp)
155: sregreq = OpenID::SReg::Request.from_openid_request(oidreq) or return
156: per_site = config[oidreq.trust_root] || {}
157:
158: sreg_data = {}
159: sregreq.all_requested_fields.each do |field|
160: sreg_data[field] = per_site[field] || config[field]
161: end
162:
163: sregresp = OpenID::SReg::Response.extract_response(sregreq, sreg_data)
164: oidresp.add_extension(sregresp)
165: end
if a single-user OpenID provider like us is being hit by multiple clients at once, then something is seriously wrong. Can’t use Mutexes here since somebody could be running this as a CGI script
# File bin/local-openid, line 289
289: def big_lock(&block)
290: lock = "#$local_openid/lock"
291: File.open(lock, File::WRONLY|File::CREAT|File::EXCL, 0600) do |fp|
292: begin
293: yield
294: ensure
295: File.unlink(lock)
296: end
297: end
298: rescue Errno::EEXIST
299: err("Lock: #{lock} exists! Possible hijacking attempt") rescue nil
300: end
(Not documented)
# File bin/local-openid, line 238
238: def config
239: @config ||= begin
240: YAML.load(File.read("#$local_openid/config.yml"))
241: rescue Errno::ENOENT
242: {}
243: end
244: end
(Not documented)
# File bin/local-openid, line 180
180: def err(msg)
181: env['rack.errors'].write("#{msg}\n")
182: false
183: end
(Not documented)
# File bin/local-openid, line 185
185: def finalize_response(oidresp)
186: server.signatory.sign(oidresp) if oidresp.needs_signing
187: web_response = server.encode_response(oidresp)
188:
189: case web_response.code
190: when HTTP_OK
191: web_response.body
192: when HTTP_REDIRECT
193: location = web_response.headers['location']
194: err("redirecting to: #{location} ...")
195: redirect(location)
196: else
197: halt(500, web_response.body)
198: end
199: end
this is the heart of our provider logic, adapted from the Ruby OpenID gem Rails example
# File bin/local-openid, line 102
102: def get_or_post
103: oidreq = begin
104: server.decode_request(params)
105: rescue ProtocolError => err
106: halt(500, err.to_s)
107: end
108:
109: oidreq or return render_xrds
110:
111: oidresp = case oidreq
112: when CheckIDRequest
113: if oidreq.id_select && oidreq.immediate
114: oidreq.answer(false)
115: elsif is_authorized?(oidreq)
116: resp = oidreq.answer(true, nil, server_root)
117: add_sreg(oidreq, resp)
118: add_pape(oidreq, resp)
119: resp
120: elsif oidreq.immediate
121: oidreq.answer(false, server_root)
122: else
123: session[:id] ||= "#{Time.now.to_i}.#$$.#{rand}"
124: session[:ip] = request.ip
125: merge_config(oidreq)
126: write_config
127:
128: # here we allow our user to open $EDITOR and edit the appropriate
129: # 'expires' field in config.yml corresponding to oidreq.trust_root
130: return PROMPT.gsub(/%s/, oidreq.trust_root)
131: end
132: else
133: server.handle_request(oidreq)
134: end
135:
136: finalize_response(oidresp)
137: end
(Not documented)
# File bin/local-openid, line 246
246: def merge_config(oidreq)
247: per_site = config[oidreq.trust_root] ||= {}
248: per_site.merge!({
249: 'assoc_handle' => oidreq.assoc_handle,
250: 'expires' => Time.at(0).utc,
251: 'updated' => Time.now.utc,
252: 'expires1m' => Time.now.utc + 60, # easy edit to "expires" in $EDITOR
253: 'session_id' => session[:id],
254: })
255: end
this output is designed to be parsed by OpenID consumers
# File bin/local-openid, line 269
269: def render_xrds(force = false)
270: if force || request.accept.include?('application/xrds+xml')
271:
272: # this seems to work...
273: types = request.accept.include?('application/xrds+xml') ?
274: [ OpenID::OPENID_2_0_TYPE, OpenID::OPENID_1_0_TYPE, OpenID::SREG_URI ] :
275: [ OpenID::OPENID_IDP_2_0_TYPE ]
276:
277: headers['Content-Type'] = 'application/xrds+xml'
278: types = types.map { |uri| "<Type>#{uri}</Type>" }.join("\n")
279: XRDS_XML.gsub(/%s/, server_root).gsub!(/%types/, types)
280: else # render a browser-friendly page with an XRDS pointer
281: headers['X-XRDS-Location'] = "#{server_root}xrds"
282: XRDS_HTML.gsub(/%s/, server_root)
283: end
284: end
(Not documented)
# File bin/local-openid, line 146
146: def server
147: @server ||= Server.new(
148: OpenID::Store::Filesystem.new("#$local_openid/store"),
149: server_root)
150: end
we’re the provider for exactly one identity. However, we do rely on being proxied and being hit with an appropriate HTTP Host: header. Don’t expect OpenID consumers to handle port != 80.
# File bin/local-openid, line 142
142: def server_root
143: "http://#{request.host}/"
144: end
(Not documented)
# File bin/local-openid, line 257
257: def write_config
258: path = "#$local_openid/config.yml"
259: tmp = Tempfile.new('config.yml', File.dirname(path))
260: tmp.syswrite(CONFIG_HEADER.gsub(/^/m, "# "))
261: tmp.syswrite(config.to_yaml)
262: tmp.syswrite(CONFIG_TRAILER.gsub(/^/m, "# "))
263: tmp.fsync
264: File.rename(tmp.path, path)
265: tmp.close!
266: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.