pape.rb
179 lines
| 5.9 KiB
| text/x-ruby
|
RubyLexer
|
r2376 | # An implementation of the OpenID Provider Authentication Policy | ||
# Extension 1.0 | ||||
# see: http://openid.net/specs/ | ||||
require 'openid/extension' | ||||
module OpenID | ||||
module PAPE | ||||
NS_URI = "http://specs.openid.net/extensions/pape/1.0" | ||||
AUTH_MULTI_FACTOR_PHYSICAL = | ||||
'http://schemas.openid.net/pape/policies/2007/06/multi-factor-physical' | ||||
AUTH_MULTI_FACTOR = | ||||
'http://schemas.openid.net/pape/policies/2007/06/multi-factor' | ||||
AUTH_PHISHING_RESISTANT = | ||||
'http://schemas.openid.net/pape/policies/2007/06/phishing-resistant' | ||||
TIME_VALIDATOR = /\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/ | ||||
# A Provider Authentication Policy request, sent from a relying | ||||
# party to a provider | ||||
class Request < Extension | ||||
attr_accessor :preferred_auth_policies, :max_auth_age, :ns_alias, :ns_uri | ||||
def initialize(preferred_auth_policies=[], max_auth_age=nil) | ||||
@ns_alias = 'pape' | ||||
@ns_uri = NS_URI | ||||
@preferred_auth_policies = preferred_auth_policies | ||||
@max_auth_age = max_auth_age | ||||
end | ||||
# Add an acceptable authentication policy URI to this request | ||||
# This method is intended to be used by the relying party to add | ||||
# acceptable authentication types to the request. | ||||
def add_policy_uri(policy_uri) | ||||
unless @preferred_auth_policies.member? policy_uri | ||||
@preferred_auth_policies << policy_uri | ||||
end | ||||
end | ||||
def get_extension_args | ||||
ns_args = { | ||||
'preferred_auth_policies' => @preferred_auth_policies.join(' ') | ||||
} | ||||
ns_args['max_auth_age'] = @max_auth_age.to_s if @max_auth_age | ||||
return ns_args | ||||
end | ||||
# Instantiate a Request object from the arguments in a | ||||
# checkid_* OpenID message | ||||
# return nil if the extension was not requested. | ||||
def self.from_openid_request(oid_req) | ||||
pape_req = new | ||||
args = oid_req.message.get_args(NS_URI) | ||||
if args == {} | ||||
return nil | ||||
end | ||||
pape_req.parse_extension_args(args) | ||||
return pape_req | ||||
end | ||||
# Set the state of this request to be that expressed in these | ||||
# PAPE arguments | ||||
def parse_extension_args(args) | ||||
@preferred_auth_policies = [] | ||||
policies_str = args['preferred_auth_policies'] | ||||
if policies_str | ||||
policies_str.split(' ').each{|uri| | ||||
add_policy_uri(uri) | ||||
} | ||||
end | ||||
max_auth_age_str = args['max_auth_age'] | ||||
if max_auth_age_str | ||||
@max_auth_age = max_auth_age_str.to_i | ||||
else | ||||
@max_auth_age = nil | ||||
end | ||||
end | ||||
# Given a list of authentication policy URIs that a provider | ||||
# supports, this method returns the subset of those types | ||||
# that are preferred by the relying party. | ||||
def preferred_types(supported_types) | ||||
@preferred_auth_policies.select{|uri| supported_types.member? uri} | ||||
end | ||||
end | ||||
# A Provider Authentication Policy response, sent from a provider | ||||
# to a relying party | ||||
class Response < Extension | ||||
attr_accessor :ns_alias, :auth_policies, :auth_time, :nist_auth_level | ||||
def initialize(auth_policies=[], auth_time=nil, nist_auth_level=nil) | ||||
@ns_alias = 'pape' | ||||
@ns_uri = NS_URI | ||||
@auth_policies = auth_policies | ||||
@auth_time = auth_time | ||||
@nist_auth_level = nist_auth_level | ||||
end | ||||
# Add a policy URI to the response | ||||
# see http://openid.net/specs/openid-provider-authentication-policy-extension-1_0-01.html#auth_policies | ||||
def add_policy_uri(policy_uri) | ||||
@auth_policies << policy_uri unless @auth_policies.member?(policy_uri) | ||||
end | ||||
# Create a Response object from an OpenID::Consumer::SuccessResponse | ||||
def self.from_success_response(success_response) | ||||
args = success_response.get_signed_ns(NS_URI) | ||||
return nil if args.nil? | ||||
pape_resp = new | ||||
pape_resp.parse_extension_args(args) | ||||
return pape_resp | ||||
end | ||||
# parse the provider authentication policy arguments into the | ||||
# internal state of this object | ||||
# if strict is specified, raise an exception when bad data is | ||||
# encountered | ||||
def parse_extension_args(args, strict=false) | ||||
policies_str = args['auth_policies'] | ||||
if policies_str and policies_str != 'none' | ||||
@auth_policies = policies_str.split(' ') | ||||
end | ||||
nist_level_str = args['nist_auth_level'] | ||||
if nist_level_str | ||||
# special handling of zero to handle to_i behavior | ||||
if nist_level_str.strip == '0' | ||||
nist_level = 0 | ||||
else | ||||
nist_level = nist_level_str.to_i | ||||
# if it's zero here we have a bad value | ||||
if nist_level == 0 | ||||
nist_level = nil | ||||
end | ||||
end | ||||
if nist_level and nist_level >= 0 and nist_level < 5 | ||||
@nist_auth_level = nist_level | ||||
elsif strict | ||||
raise ArgumentError, "nist_auth_level must be an integer 0 through 4, not #{nist_level_str.inspect}" | ||||
end | ||||
end | ||||
auth_time_str = args['auth_time'] | ||||
if auth_time_str | ||||
# validate time string | ||||
if auth_time_str =~ TIME_VALIDATOR | ||||
@auth_time = auth_time_str | ||||
elsif strict | ||||
raise ArgumentError, "auth_time must be in RFC3339 format" | ||||
end | ||||
end | ||||
end | ||||
def get_extension_args | ||||
ns_args = {} | ||||
if @auth_policies.empty? | ||||
ns_args['auth_policies'] = 'none' | ||||
else | ||||
ns_args['auth_policies'] = @auth_policies.join(' ') | ||||
end | ||||
if @nist_auth_level | ||||
unless (0..4).member? @nist_auth_level | ||||
raise ArgumentError, "nist_auth_level must be an integer 0 through 4, not #{@nist_auth_level.inspect}" | ||||
end | ||||
ns_args['nist_auth_level'] = @nist_auth_level.to_s | ||||
end | ||||
if @auth_time | ||||
unless @auth_time =~ TIME_VALIDATOR | ||||
raise ArgumentError, "auth_time must be in RFC3339 format" | ||||
end | ||||
ns_args['auth_time'] = @auth_time | ||||
end | ||||
return ns_args | ||||
end | ||||
end | ||||
end | ||||
end | ||||