File: pape.rb

package info (click to toggle)
ruby-openid 2.5.0debian-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,980 kB
  • ctags: 2,219
  • sloc: ruby: 16,737; xml: 219; sh: 24; makefile: 2
file content (179 lines) | stat: -rw-r--r-- 6,083 bytes parent folder | download | duplicates (8)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# 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