Class: CAS::Filter

Inherits:
Object
  • Object
show all
Defined in:
lib/cas_auth.rb

Overview

Allows authentication through a CAS server. The precondition for this filter to work is that you have an authentication infrastructure. As such, this is for the enterprise rather than small shops.

To use CAS::Filter for authentication, add something like this to your environment:

CAS::Filter.server_name = "yourapplication.server.name"
CAS::Filter.cas_base_url = "https://cas.company.com

The filter will try to use the standard CAS page locations based on this URL. Or you can explicitly specify the individual URLs:

CAS::Filter.server_name = "yourapplication.server.name"
CAS::Filter. = "https://cas.company.com/login"
CAS::Filter.validate_url = "https://cas.company.com/proxyValidate"

It is of course possible to use different configurations in development, test and production by placing the configuration in the appropriate environments file.

To add CAS protection to a controller:

before_filter CAS::Filter

All of the standard Rails filter qualifiers can also be used. For example:

before_filter CAS::Filter, :only => [:admin, :private]

By default CAS::Filter saves the logged in user in session but that name can be changed by setting CAS::Filter.session_username The username is also available from the request by

request.username

This wrapping of the request can be disabled by

CAS::Filter.wrap_request = false

Proxying is also possible. Please see the README for examples.

Constant Summary collapse

@@login_url =
"https://localhost/login"
@@logout_url =
nil
@@validate_url =
"https://localhost/proxyValidate"
@@server_name =
"localhost"
@@renew =
false
@@session_username =
:casfilteruser
@@query_string =
{}
@@fake =
nil
@@pgt =
nil
@@authorized_proxies =
[]

Class Method Summary collapse

Class Method Details

.cas_base_url=(url) ⇒ Object



124
125
126
127
128
129
130
# File 'lib/cas_auth.rb', line 124

def cas_base_url=(url)
  url.gsub!(/\/$/, '')
  CAS::Filter. = "#{url}/login"
  CAS::Filter.validate_url = "#{url}/proxyValidate"
  CAS::Filter.proxy_url = "#{url}/proxy"
  logger.debug "Initialized CAS base url to: #{url}"
end

.create_logout_urlObject



105
106
107
108
109
110
# File 'lib/cas_auth.rb', line 105

def create_logout_url
  if !@@logout_url && @@login_url =~ %r{^(.+?)/[^/]*$}
    @@logout_url = "#{$1}/logout"
  end
  logger.debug "Created logout url: #{@@logout_url}"
end

.fakeObject



132
133
134
# File 'lib/cas_auth.rb', line 132

def fake
  @@fake
end

.fake=(val) ⇒ Object



136
137
138
139
140
141
142
143
144
145
# File 'lib/cas_auth.rb', line 136

def fake=(val)
if val.nil?
  alias :filter :filter_r
  logger.info "Will use real filter"
else
  alias :filter :filter_f
  logger.warn "Will use fake filter"
  end
  @@fake = val
end

.filter_f(controller) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/cas_auth.rb', line 147

def filter_f(controller)
    logger.break
    logger.warn("Using fake CAS filter")
  username = @@fake
  if :failure == @@fake
    return false
  elsif :param == @@fake
    username = controller.params['username']
  elsif Proc === @@fake
    username = @@fake.call(controller)
  end
  logger.info("The username set by the fake filter is: #{username}")
  controller.session[@@session_username] = username
  return true
end

.filter_r(controller) ⇒ Object Also known as: filter



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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/cas_auth.rb', line 163

def filter_r(controller)
  logger.break
  logger.info("Using real CAS filter in controller: #{controller}")
  
  session_receipt = controller.session[:casfilterreceipt]
  session_ticket = controller.session[:caslastticket]
  ticket = controller.params[:ticket]
  
  is_valid = false
  
  if ticket and (!session_ticket or session_ticket != ticket)
    log.info "A ticket parameter was given in the URI: #{ticket} and "+
      (!session_ticket ? "there is no previous ticket for this session" : 
          "the ticket is different than the previous ticket, which was #{session_ticket}")
  
    receipt = get_receipt_for_ticket(ticket, controller)
    
    if receipt && validate_receipt(receipt)
      logger.info("Receipt for ticket request #{ticket} is valid, belongs to user #{receipt.user_name}, and will be stored in the session.")
      controller.session[:casfilterreceipt] = receipt
      controller.session[:caslastticket] = ticket
      controller.session[@@session_username] = receipt.user_name
      
      if receipt.pgt_iou
        logger.info("Receipt has a proxy-granting ticket IOU. Attempting to retrieve the proxy-granting ticket...")
        pgt = retrieve_pgt(receipt)
        if pgt
          log.debug("Got PGT #{pgt} for PGT IOU #{receipt.pgt_iou}. This will be stored in the session.")
          controller.session[:casfilterpgt] = pgt
        else
          log.error("Failed to retrieve a PGT for PGT IOU #{receipt.pgt_iou}!")
        end
      end
      
      is_valid = true
    else
      if receipt
        log.warn "Receipt was invalid for ticket #{ticket}!"
      else
        log.warn "get_receipt_for_ticket() for ticket #{ticket} did not return a receipt!"
      end
    end
    
  elsif session_receipt
  
    log.info "Validating receipt from the session because " + 
      (ticket ? "the given ticket #{ticket} is the same as the old ticket" : "there was no ticket given in the URI") + "."
    log.debug "The session receipt is: #{session_receipt}"
    
    is_valid = validate_receipt(session_receipt)
    
    if is_valid
      log.info "The session receipt is VALID"
    else 
      log.warn "The session receipt is NOT VALID!"
    end
    
  else
    
    log.info "No ticket was given and we do not have a receipt in the session."
  
    did_gateway = controller.session[:casfiltergateway]
    raise CASException, "Can't redirect without login url" unless @@login_url
    
    if did_gateway
      if controller.session[@@session_username]
        log.info "We gatewayed and have a username stored in the session. The gateway was therefore successful."
        is_valid = true
      else
        log.debug "We gatewayed but do not have a username stored in the session, so we will keep session[:casfiltergateway] true"
        controller.session[:casfiltergateway] = true
      end
    else
      log.info "We did not gateway, so we will notify the filter that the next request is being gatewayed by setting sesson[:casfiltergateway} to true"
      controller.session[:casfiltergateway] = true
    end
    
  end
  
  if is_valid
    logger.info "This request is successfully CAS authenticated for user #{controller.session[@@session_username]}!"
    return true
  else
    controller.session[:service] = service_url(controller)
    logger.info "This request is NOT CAS authenticated, so we will redirect to the login page at: #{redirect_url(controller)}"
      controller.send :redirect_to, redirect_url(controller) and return false
  end
end

.loggerObject Also known as: log

Retrieves the current Logger instance



95
96
97
# File 'lib/cas_auth.rb', line 95

def logger
  CAS::LOGGER
end

.logger=(val) ⇒ Object Also known as: log=



98
99
100
# File 'lib/cas_auth.rb', line 98

def logger=(val)
  CAS::LOGGER.set_logger(val)
end

.logout_url(controller) ⇒ Object



112
113
114
115
116
117
# File 'lib/cas_auth.rb', line 112

def logout_url(controller)
  create_logout_url unless @@logout_url
  url = redirect_url(controller,@@logout_url)
  logger.debug "Logout url is: #{url}"
  url
end

.logout_url=(url) ⇒ Object



119
120
121
122
# File 'lib/cas_auth.rb', line 119

def logout_url=(url)
  @@logout_url = url
  logger.debug "Initialized logout url to: #{url}"
end

.request_proxy_ticket(target_service, pgt) ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/cas_auth.rb', line 254

def request_proxy_ticket(target_service, pgt)
  r = ProxyTicketRequest.new
  r.proxy_url = @@proxy_url
  r.target_service = target_service
  r.pgt = pgt
  
  raise CAS::ProxyGrantingNotAvailable, "Cannot request a proxy ticket for service #{r.target_service} because no proxy granting ticket (PGT) has been set." unless r.pgt
  
  logger.info("Requesting proxy ticket for service: #{r.target_service} with PGT #{pgt}")
  r.request
  
  if r.proxy_ticket
    logger.info("Got proxy ticket #{r.proxy_ticket} for service #{r.target_service}")
  else
    logger.warn("Did not receive a proxy ticket for service #{r.target_service}! Reason: #{r.error_code}: #{r.error_message}")
  end
  
  return r
end