File: checkid_request.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 (186 lines) | stat: -rw-r--r-- 7,372 bytes parent folder | download | duplicates (5)
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
180
181
182
183
184
185
186
require "openid/message"
require "openid/util"

module OpenID
  class Consumer
    # An object that holds the state necessary for generating an
    # OpenID authentication request. This object holds the association
    # with the server and the discovered information with which the
    # request will be made.
    #
    # It is separate from the consumer because you may wish to add
    # things to the request before sending it on its way to the
    # server. It also has serialization options that let you encode
    # the authentication request as a URL or as a form POST.
    class CheckIDRequest
      attr_accessor :return_to_args, :message
      attr_reader :endpoint

      # Users of this library should not create instances of this
      # class.  Instances of this class are created by the library
      # when needed.
      def initialize(assoc, endpoint)
        @assoc = assoc
        @endpoint = endpoint
        @return_to_args = {}
        @message = Message.new(endpoint.preferred_namespace)
        @anonymous = false
      end

      attr_reader :anonymous

      # Set whether this request should be made anonymously. If a
      # request is anonymous, the identifier will not be sent in the
      # request. This is only useful if you are making another kind of
      # request with an extension in this request.
      #
      # Anonymous requests are not allowed when the request is made
      # with OpenID 1.
      def anonymous=(is_anonymous)
        if is_anonymous && @message.is_openid1
          raise ArgumentError, ("OpenID1 requests MUST include the "\
                                "identifier in the request")
        end
        @anonymous = is_anonymous
      end

      # Add an object that implements the extension interface for
      # adding arguments to an OpenID message to this checkid request.
      #
      # extension_request: an OpenID::Extension object.
      def add_extension(extension_request)
        extension_request.to_message(@message)
      end

      # Add an extension argument to this OpenID authentication
      # request. You probably want to use add_extension and the
      # OpenID::Extension interface.
      #
      # Use caution when adding arguments, because they will be
      # URL-escaped and appended to the redirect URL, which can easily
      # get quite long.
      def add_extension_arg(namespace, key, value)
        @message.set_arg(namespace, key, value)
      end

      # Produce a OpenID::Message representing this request.
      #
      # Not specifying a return_to URL means that the user will not be
      # returned to the site issuing the request upon its completion.
      #
      # If immediate mode is requested, the OpenID provider is to send
      # back a response immediately, useful for behind-the-scenes
      # authentication attempts.  Otherwise the OpenID provider may
      # engage the user before providing a response.  This is the
      # default case, as the user may need to provide credentials or
      # approve the request before a positive response can be sent.
      def get_message(realm, return_to=nil, immediate=false)
        if !return_to.nil?
          return_to = Util.append_args(return_to, @return_to_args)
        elsif immediate
          raise ArgumentError, ('"return_to" is mandatory when using '\
                                '"checkid_immediate"')
        elsif @message.is_openid1
          raise ArgumentError, ('"return_to" is mandatory for OpenID 1 '\
                                'requests')
        elsif @return_to_args.empty?
          raise ArgumentError, ('extra "return_to" arguments were specified, '\
                                'but no return_to was specified')
        end


        message = @message.copy

        mode = immediate ? 'checkid_immediate' : 'checkid_setup'
        message.set_arg(OPENID_NS, 'mode', mode)

        realm_key = message.is_openid1 ? 'trust_root' : 'realm'
        message.set_arg(OPENID_NS, realm_key, realm)

        if !return_to.nil?
          message.set_arg(OPENID_NS, 'return_to', return_to)
        end

        if not @anonymous
          if @endpoint.is_op_identifier
            # This will never happen when we're in OpenID 1
            # compatibility mode, as long as is_op_identifier()
            # returns false whenever preferred_namespace returns
            # OPENID1_NS.
            claimed_id = request_identity = IDENTIFIER_SELECT
          else
            request_identity = @endpoint.get_local_id
            claimed_id = @endpoint.claimed_id
          end

          # This is true for both OpenID 1 and 2
          message.set_arg(OPENID_NS, 'identity', request_identity)

          if message.is_openid2
            message.set_arg(OPENID2_NS, 'claimed_id', claimed_id)
          end
        end

        if @assoc && (message.is_openid1 || !['checkid_setup', 'checkid_immediate'].include?(mode))
          message.set_arg(OPENID_NS, 'assoc_handle', @assoc.handle)
          assoc_log_msg = "with assocication #{@assoc.handle}"
        else
          assoc_log_msg = 'using stateless mode.'
        end

        Util.log("Generated #{mode} request to #{@endpoint.server_url} "\
                 "#{assoc_log_msg}")
        return message
      end

      # Returns a URL with an encoded OpenID request.
      #
      # The resulting URL is the OpenID provider's endpoint URL with
      # parameters appended as query arguments.  You should redirect
      # the user agent to this URL.
      #
      # OpenID 2.0 endpoints also accept POST requests, see
      # 'send_redirect?' and 'form_markup'.
      def redirect_url(realm, return_to=nil, immediate=false)
        message = get_message(realm, return_to, immediate)
        return message.to_url(@endpoint.server_url)
      end

      # Get html for a form to submit this request to the IDP.
      #
      # form_tag_attrs is a hash of attributes to be added to the form
      # tag. 'accept-charset' and 'enctype' have defaults that can be
      # overridden. If a value is supplied for 'action' or 'method',
      # it will be replaced.
      def form_markup(realm, return_to=nil, immediate=false,
                      form_tag_attrs=nil)
        message = get_message(realm, return_to, immediate)
        return message.to_form_markup(@endpoint.server_url, form_tag_attrs)
      end

      # Get a complete HTML document that autosubmits the request to the IDP
      # with javascript.  This method wraps form_markup - see that method's
      # documentation for help with the parameters.
      def html_markup(realm, return_to=nil, immediate=false,
                      form_tag_attrs=nil)
        Util.auto_submit_html(form_markup(realm, 
                                          return_to, 
                                          immediate, 
                                          form_tag_attrs))
      end

      # Should this OpenID authentication request be sent as a HTTP
      # redirect or as a POST (form submission)?
      #
      # This takes the same parameters as redirect_url or form_markup
      def send_redirect?(realm, return_to=nil, immediate=false)
        if @endpoint.compatibility_mode
          return true
        else
          url = redirect_url(realm, return_to, immediate)
          return url.length <= OPENID1_URL_LIMIT
        end
      end
    end
  end
end