Upgraded Rails and RSpec
[monkeycharger.git] / vendor / rails / actionpack / lib / action_controller / http_authentication.rb
blob18a503c3ad23c47ceea1a48c862edd4c4fc0c298
1 require 'base64'
3 module ActionController
4   module HttpAuthentication
5     # Makes it dead easy to do HTTP Basic authentication.
6     # 
7     # Simple Basic example:
8     # 
9     #   class PostsController < ApplicationController
10     #     USER_NAME, PASSWORD = "dhh", "secret"
11     #   
12     #     before_filter :authenticate, :except => [ :index ]
13     #   
14     #     def index
15     #       render :text => "Everyone can see me!"
16     #     end
17     #   
18     #     def edit
19     #       render :text => "I'm only accessible if you know the password"
20     #     end
21     #   
22     #     private
23     #       def authenticate
24     #         authenticate_or_request_with_http_basic do |user_name, password| 
25     #           user_name == USER_NAME && password == PASSWORD
26     #         end
27     #       end
28     #   end
29     # 
30     # 
31     # Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication, 
32     # the regular HTML interface is protected by a session approach:
33     # 
34     #   class ApplicationController < ActionController::Base
35     #     before_filter :set_account, :authenticate
36     #   
37     #     protected
38     #       def set_account
39     #         @account = Account.find_by_url_name(request.subdomains.first)
40     #       end
41     #   
42     #       def authenticate
43     #         case request.format
44     #         when Mime::XML, Mime::ATOM
45     #           if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
46     #             @current_user = user
47     #           else
48     #             request_http_basic_authentication
49     #           end
50     #         else
51     #           if session_authenticated?
52     #             @current_user = @account.users.find(session[:authenticated][:user_id])
53     #           else
54     #             redirect_to(login_url) and return false
55     #           end
56     #         end
57     #       end
58     #   end
59     # 
60     # 
61     # In your integration tests, you can do something like this:
62     # 
63     #   def test_access_granted_from_xml
64     #     get(
65     #       "/notes/1.xml", nil, 
66     #       :authorization => ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
67     #     )
68     # 
69     #     assert_equal 200, status
70     #   end
71     #  
72     #  
73     # On shared hosts, Apache sometimes doesn't pass authentication headers to
74     # FCGI instances. If your environment matches this description and you cannot
75     # authenticate, try this rule in public/.htaccess (replace the plain one):
76     # 
77     #   RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
78     module Basic
79       extend self
81       module ControllerMethods
82         def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
83           authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
84         end
86         def authenticate_with_http_basic(&login_procedure)
87           HttpAuthentication::Basic.authenticate(self, &login_procedure)
88         end
90         def request_http_basic_authentication(realm = "Application")
91           HttpAuthentication::Basic.authentication_request(self, realm)
92         end
93       end
95       def authenticate(controller, &login_procedure)
96         unless authorization(controller.request).blank?
97           login_procedure.call(*user_name_and_password(controller.request))
98         end
99       end
101       def user_name_and_password(request)
102         decode_credentials(request).split(/:/, 2)
103       end
104   
105       def authorization(request)
106         request.env['HTTP_AUTHORIZATION']   ||
107         request.env['X-HTTP_AUTHORIZATION'] ||
108         request.env['X_HTTP_AUTHORIZATION'] ||
109         request.env['REDIRECT_X_HTTP_AUTHORIZATION']
110       end
111     
112       def decode_credentials(request)
113         Base64.decode64(authorization(request).split.last || '')
114       end
116       def encode_credentials(user_name, password)
117         "Basic #{Base64.encode64("#{user_name}:#{password}")}"
118       end
120       def authentication_request(controller, realm)
121         controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}")
122         controller.send! :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized
123       end
124     end
125   end