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
# 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
  
  if $CONF[:authenticator].instance_of? Array
    $AUTH.each_index {|auth_index| $AUTH[auth_index].configure($CONF.authenticator[auth_index])}
  else
    $AUTH[0].configure($CONF.authenticator)
  end

  $LOG.debug("Logging in with username: #{@username}, lt: #{@lt}, service: #{@service}, auth: #{$AUTH}")
  
  credentials_are_valid = false
  extra_attributes = {}
  successful_authenticator = nil
  begin
    $AUTH.each do |auth|
      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
    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)
    
    if $CONF.maximum_session_lifetime
      expires = $CONF.maximum_session_lifetime.to_i.from_now
      expiry_info = " It will expire on #{expires}."
    else
      expiry_info = " It will not expire."
    end
    
    if $CONF.maximum_session_lifetime
      cookies['tgt'] = {
        :value => tgt.to_s, 
        :expires => Time.now + $CONF.maximum_session_lifetime
      }
    else
      cookies['tgt'] = tgt.to_s
    end
    
    $LOG.debug("Ticket granting cookie '#{cookies['tgt'].inspect}' granted to #{@username.inspect}. #{expiry_info}")
            
    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
end