Class: CASServer::Controllers::Login

Inherits:
R
  • Object
show all
Includes:
CASServer::CAS
Defined in:
lib/casserver/controllers.rb

Overview

2.1

Instance Method Summary collapse

Methods included from CASServer::CAS

clean_service_url, #generate_login_ticket, #generate_proxy_granting_ticket, #generate_proxy_ticket, #generate_service_ticket, #generate_ticket_granting_ticket, #send_logout_notification_for_service_ticket, #service_uri_with_ticket, #validate_login_ticket, #validate_proxy_granting_ticket, #validate_proxy_ticket, #validate_service_ticket, #validate_ticket_granting_ticket

Instance Method Details

#getObject

2.1.1



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
# File 'lib/casserver/controllers.rb', line 13

def get
  CASServer::Utils::log_controller_action(self.class, input)

  # make sure there's no caching
  headers['Pragma'] = 'no-cache'
  headers['Cache-Control'] = 'no-store'
  headers['Expires'] = (Time.now - 1.year).rfc2822

  # optional params
  @service = clean_service_url(input['service'])
  @renew = input['renew']
  @gateway = input['gateway'] == 'true' || input['gateway'] == '1'

  if tgc = cookies['tgt']
    tgt, tgt_error = validate_ticket_granting_ticket(tgc)
  end

  if tgt and !tgt_error
    @message = {:type => 'notice',
      :message => _("You are currently logged in as '%s'. If this is not you, please log in below.") % tgt.username }
  end

  if input['redirection_loop_intercepted']
    @message = {:type => 'mistake',
      :message => _("The client and server are unable to negotiate authentication. Please try logging in again later.")}
  end

  begin
    if @service
      if !@renew && tgt && !tgt_error
        st = generate_service_ticket(@service, tgt.username, tgt)
        service_with_ticket = service_uri_with_ticket(@service, st)
        $LOG.info("User '#{tgt.username}' authenticated based on ticket granting cookie. Redirecting to service '#{@service}'.")
        return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
      elsif @gateway
        $LOG.info("Redirecting unauthenticated gateway request to service '#{@service}'.")
        return redirect(@service, :status => 303)
      end
    elsif @gateway
        $LOG.error("This is a gateway request but no service parameter was given!")
        @message = {:type => 'mistake',
          :message => _("The server cannot fulfill this gateway request because no service parameter was given.")}
    end
  rescue URI::InvalidURIError
    $LOG.error("The service '#{@service}' is not a valid URI!")
    @message = {:type => 'mistake',
      :message => _("The target service your browser supplied appears to be invalid. Please contact your system administrator for help.")}
  end

  lt = 

  $LOG.debug("Rendering login form with lt: #{lt}, service: #{@service}, renew: #{@renew}, gateway: #{@gateway}")

  @lt = lt.ticket

  #$LOG.debug(env)

  # If the 'onlyLoginForm' parameter is specified, we will only return the
  # login form part of the page. This is useful for when you want to
  # embed the login form in some external page (as an IFRAME, or otherwise).
  # The optional 'submitToURI' parameter can be given to explicitly set the
  # action for the form, otherwise the server will try to guess this for you.
  if input.has_key? 'onlyLoginForm'
    if @env['HTTP_HOST']
       = "http#{@env['HTTPS'] && @env['HTTPS'] == 'on' ? 's' : ''}://#{@env['REQUEST_URI']}#{self / '/login'}"
    else
       = nil
    end

    @form_action = input['submitToURI'] || 

    if @form_action
      render :login_form
    else
      @status = 500
      _("Could not guess the CAS login URI. Please supply a submitToURI parameter with your request.")
    end
  else
    render :login
  end
end

#postObject

2.2



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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/casserver/controllers.rb', line 96

def post
  CASServer::Utils::log_controller_action(self.class, input)

  # 2.2.1 (optional)
  @service = clean_service_url(input['service'])

  # 2.2.2 (required)
  @username = input['username']
  @password = input['password']
  @lt = input['lt']

  # Remove leading and trailing widespace from username.
  @username.strip! if @username

  if @username && $CONF[:downcase_username]
    $LOG.debug("Converting username #{@username.inspect} to lowercase because 'downcase_username' option is enabled.")
    @username.downcase!
  end

  if error = (@lt)
    @message = {:type => 'mistake', :message => error}
    # generate another login ticket to allow for re-submitting the form
    @lt = .ticket
    @status = 401
    return render(:login)
  end

  # generate another login ticket to allow for re-submitting the form after a post
  @lt = .ticket

  $LOG.debug("Logging in with username: #{@username}, lt: #{@lt}, service: #{@service}, auth: #{$AUTH}")

  credentials_are_valid = false
  extra_attributes = {}
  successful_authenticator = nil
  begin
    auth_index = 0
    $AUTH.each do |auth_class|
      auth = auth_class.new

      auth.configure($CONF.authenticator[auth_index].merge(:auth_index => auth_index))

      credentials_are_valid = auth.validate(
        :username => @username,
        :password => @password,
        :service => @service,
        :request => @env
      )
      if credentials_are_valid
        extra_attributes.merge!(auth.extra_attributes) unless auth.extra_attributes.blank?
        successful_authenticator = auth
        break
      end

      auth_index += 1
    end
  rescue CASServer::AuthenticatorError => e
    $LOG.error(e)
    @message = {:type => 'mistake', :message => e.to_s}
    return render(:login)
  end

  if credentials_are_valid
    $LOG.info("Credentials for username '#{@username}' successfully validated using #{successful_authenticator.class.name}.")
    $LOG.debug("Authenticator provided additional user attributes: #{extra_attributes.inspect}") unless extra_attributes.blank?

    # 3.6 (ticket-granting cookie)
    tgt = generate_ticket_granting_ticket(@username, extra_attributes)
    setup_cookie_tgt(tgt)

    if @service.blank?
      $LOG.info("Successfully authenticated user '#{@username}' at '#{tgt.client_hostname}'. No service param was given, so we will not redirect.")
      @message = {:type => 'confirmation', :message => _("You have successfully logged in.")}
    else
      @st = generate_service_ticket(@service, @username, tgt)
      begin
        service_with_ticket = service_uri_with_ticket(@service, @st)

        $LOG.info("Redirecting authenticated user '#{@username}' at '#{@st.client_hostname}' to service '#{@service}'")
        return redirect(service_with_ticket, :status => 303) # response code 303 means "See Other" (see Appendix B in CAS Protocol spec)
      rescue URI::InvalidURIError
        $LOG.error("The service '#{@service}' is not a valid URI!")
        @message = {:type => 'mistake',
          :message => _("The target service your browser supplied appears to be invalid. Please contact your system administrator for help.")}
      end
    end
  else
    $LOG.warn("Invalid credentials given for user '#{@username}'")
    @message = {:type => 'mistake', :message => _("Incorrect username or password.")}
    @status = 401
  end

  render :login

  private
  def setup_cookie_tgt tgt
    expires = if $CONF.maximum_session_lifetime
                 $CONF.maximum_session_lifetime.to_i.from_now
              else
                 nil
              end

    cookies['tgt'] = if expires
                       expiry_info = " It will expire on #{expires}."

                       { :value   => tgt.to_s,
                         :expires => expires   }

                     else
                       expiry_info = " It will not expire."

                       tgt.to_s
                     end

    $LOG.debug("Ticket granting cookie '#{cookies['tgt'].inspect}' granted to #{@username.inspect}. #{expiry_info}")
  end
end


191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/casserver/controllers.rb', line 191

def setup_cookie_tgt tgt
  expires = if $CONF.maximum_session_lifetime
               $CONF.maximum_session_lifetime.to_i.from_now
            else
               nil
            end

  cookies['tgt'] = if expires
                     expiry_info = " It will expire on #{expires}."

                     { :value   => tgt.to_s,
                       :expires => expires   }

                   else
                     expiry_info = " It will not expire."

                     tgt.to_s
                   end

  $LOG.debug("Ticket granting cookie '#{cookies['tgt'].inspect}' granted to #{@username.inspect}. #{expiry_info}")
end