rack-cas-rails 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0818a3cce11d21fc1c56fe4b1e70fefbb52c1cc
4
- data.tar.gz: bad76f891b70a7c54228b4e6001623f6a5e7caef
3
+ metadata.gz: b7d484d2b59603bbedf3a28c4917a463edf86c08
4
+ data.tar.gz: 7bbe3d6ae9fdbf53eef3fcb523c1d019d1afe1f1
5
5
  SHA512:
6
- metadata.gz: 6549563c5255ef7d4864b66566774744dd58ef2e104f3620325599fb4cd720e625b9fe6fe5d0ef6e36a85c1f85de7fe34abf70eaae2ae5b2a2073f8b116d17f2
7
- data.tar.gz: 79dd96b5624f71039b3facbfe1aed8bb39c7b9898a827345f753211e8aee422fb1a590ffb913e289cd17bdecb1b598cb71e06a6be6365c4c1a6fa31ba93fef4d
6
+ metadata.gz: 26517014d8fc90148db433d49e79084aa83fb2d7697174e1e9b201b5d98eae5d2e04ce784b659eb68a2d3fecf860241aa57e4aca33d2d1fd30c2d6d7f7c7ccbf
7
+ data.tar.gz: 2413da86e88601ae8995cb1813b4d429a8c3f1dfa0ae9b0f836d5e95240c9e34b1d48ee7a80d454cd2a1161be6586eb2971e8fce19da26e3847e6cd4dd1e2c24
data/README.md CHANGED
@@ -1,104 +1,223 @@
1
1
  # rack-cas-rails
2
2
 
3
- While [rbCAS/CASinoApp](http://rbcas.com) and [biola/rack-cas](https://github.com/biola/rack-cas) are both great
4
- and wonderful, there is gap between them. Namely, the bits needed to enable a Rails application to use rack-cas to integrate with
5
- CASinoApp for authentication are still missing.
3
+ [rbCAS/CASinoApp](https://github.com/rbcas/casinoapp) is a great single sign-on authentication server, and
4
+ [biola/rack-cas](https://github.com/biola/rack-cas) provides a simple means to integrate with it. However, these two things
5
+ coupled with your Rails application do not a **single sign-on enabled application** make. That is, there are still some bits
6
+ missing.
6
7
 
7
- This gem aims to fill in this void.
8
+ This gem aims to provide some of the bits to close the gap.
8
9
 
9
10
  ## Installation
10
11
 
11
- Add the following line to a Rails application's Gemfile:
12
+ Add the following to your Rails application's Gemfile:
12
13
 
13
14
  ```ruby
14
15
  gem "rack-cas-rails"
15
16
  ```
16
17
 
17
- Then open up your config/application.rb file, and add the following:
18
+ Then run
19
+
20
+ ```ruby
21
+ bundle install
22
+ ```
18
23
 
19
24
  ## Requirements
20
25
 
21
26
  The rack-cas-rails gem relies on the following:
22
27
 
23
- * A CAS-compliant server, such as [CASinoApp](http://rbcas.com)
28
+ * A working installation of [CASinoApp](http://rbcas.com), although theoretically it should work with any CAS-compliant server
24
29
  * [rack-cas](https://github.com/biola/rack-cas)
25
30
  * [rails](http://rubyonrails.org/)
26
31
 
32
+ Having access to a working CAS-compliant server is a pre-requisite. [CASinoApp](http://rbcas.com) is a simple one to set up and
33
+ use, especially if you go with the ***directly on your server*** option. Whiichever CAS server you go with, you'll need to
34
+ know the password of at least one login for testing purposes.
35
+
36
+ ### Disclaimer
37
+
38
+ I don't have access to any other CAS servers except an instance of CASinoApp I have installed and configured. So I have
39
+ only ever developed and tested against it. If you are able to try it against others, please let me know how well it works.
40
+
27
41
  ## Basic Usage
28
42
 
29
- The first thing you need to do is to make your Application class (file ```config/application.rb```) aware of the CAS-compliant
30
- server you are integrating with by pointing out its base URL, like so:
43
+ Now that you have access to a functioning CAS-compliant server, the next thing you need to do is to make your ```Rails::Application```
44
+ subclass aware of the server you are integrating with by pointing out its base URL, as shown here.
45
+
46
+ Note that setting the ```@cas_server_url``` variable is important as the ```login_url``` helper will make use of it.
31
47
 
32
48
  ```ruby
49
+ # config/application.rb
50
+
51
+ require "rack-cas"
33
52
  module MyGreatApplication
34
53
  class Application < Rails::Application
35
54
  # ...
36
- # URL of CAS server
37
- config.rack_cas.server_url = "https://sso.example.org/"
55
+ # Root URL of the CAS server
56
+ @cas_server_url = "https://sso.example.org/"
57
+ config.rack_cas.server_url = @cas_server_url
38
58
  end
39
59
  end
40
60
  ```
41
61
 
42
- In the simplest scenario, you'll want your entire application protected by authentication. That is, unless a user has authenticated,
43
- he can do nothing. To do so, add the following ```before_action``` callback to your ApplicationController
44
- (file ```app/controllers/application_ronctoller.rb```):
62
+ In the simplest case, you'll want your entire application protected by authentication. That is, unless a user has authenticated,
63
+ he can do nothing. To do so, add the following ```before_action``` callback to your ```ApplicationController```:
45
64
 
46
65
  ```ruby
66
+ # app/controllers/application_ronctoller.rb
67
+
68
+ require "rack_cas_rails"
47
69
  class ApplicationController < ActionController::Base
48
- # authenticate all actions for all controllers
70
+ # Prevent CSRF attacks by raising an exception.
71
+ # For APIs, you may want to use :null_session instead.
72
+ protect_from_forgery with: :exception
49
73
  before_action :authenticate!
50
- # ...
51
74
  end
52
75
  ```
53
76
 
54
- The ```authenticate!``` method will check to see if a browser session is authenticated. If it is, controller execution will continue.
55
- Otherwise, it will render the ```public/401.html``` file as well as return a HTTP status of 401.
77
+ The ```authenticate!``` helper will check to see if a browser session is authenticated. If it is, controller execution will continue.
78
+ Otherwise, it will render the ```public/401.html``` file if one exists, as well as return a HTTP status of 401.
56
79
 
57
- So, now, create a ```pubilc/401.html``` file in your application. You can simply copy an existing file, rename and change its
58
- contents.
80
+ At this point, if you fire up your application and browse to access any view of any controller subclassed from
81
+ ```ApplicationController```, the browser will get re-directed to the CAS server's log-in page.
59
82
 
60
83
  ## Helper Methods
61
84
 
62
- The rack-cas-rails gem also augments the ApplicationHelper module with these methods:
85
+ The rack-cas-rails gem also adds some helper methods:
86
+
87
+ * authenticate!
88
+ * authenticated?
89
+ * login_url
90
+ * logout_url
91
+
92
+ You have already seen ```authenticate!``` at work. The ```authenticated?``` helper allows your application to determine whether
93
+ a browser is authenticated or not and take appropriate action. When invoked, the latter two helpers will return the
94
+ CAS-integrated login and log out URLs, respectively. They, in turn, enable you to implement *partial authentication*.
95
+
96
+ ## Partial Authentication
63
97
 
64
- * login_url
65
- * logout_url
98
+ In this case, only certain portions of your application requires authentication. For example, perhaps actions that are
99
+ *read-only* need not be protected by authentication. To do this, change your ```ApplicationController``` as follows:
100
+
101
+ ```ruby
102
+ # app/controllers/application_ronctoller.rb
103
+
104
+ require "rack_cas_rails"
105
+ class ApplicationController < ActionController::Base
106
+ # Prevent CSRF attacks by raising an exception.
107
+ # For APIs, you may want to use :null_session instead.
108
+ protect_from_forgery with: :exception
109
+ before_action :authenticate!, except: [:index, :show]
110
+ end
111
+ ```
112
+
113
+ Restart your application and browse to a *read-only* endpoint like ```/index``` or ```/show```, and you will not be re-directed
114
+ to the CAS log-in page. But if you browse to other endpoints like ```/new```, you will be re-directed and prompted to
115
+ authenticate.
116
+
117
+ Go back and look at the read-only endpoint. It would be nice to have some indication telling a user whether he's logged in or not.
118
+ So, open up your application layout and add a ```<div>``` container that will behave differently bepending on the authentication
119
+ status of a browser session.
120
+
121
+ ```erb
122
+ <!-- views/layouts/application.html.erb -->
123
+
124
+ <!DOCTYPE html>
125
+ <html>
126
+ <head>
127
+ <title>MyGreatApplication</title>
128
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
129
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
130
+ <%= csrf_meta_tags %>
131
+ </head>
132
+ <body>
133
+ <div id="header">
134
+ <% if authenticated? %>
135
+ <span>You are logged in.</span>
136
+ <span style="float:right"><%= link_to "Logout", logout_url %></span>
137
+ <% else %>
138
+ <span>You are not logged in.</span>
139
+ <span style="float:right"><%= link_to "Login", login_url %></span>
140
+ <% end %>
141
+ </div>
142
+ <hr />
143
+ <div>
144
+ <%= yield %>
145
+ </div>
146
+ </body>
147
+ </html>
148
+ ```
66
149
 
67
- When invoked, these helpers will renturn the CAS-integrated login in and log out URLs, respectively.
150
+ Refresh your browser. This time you'll see that you're not logged in, but you are also given a login URL. Click on it, and you'll
151
+ be prompted to log-in once again.
68
152
 
69
153
  ## What Is Still Missing
70
154
 
71
- Even with the rack-cas and rack-cas-rails gems, the aforementioned basic authentication scheme is still incomplete. Namely, for an
72
- authenticated session, which user does it belong to?
155
+ However, the basic authentication scheme we have cooked up is still incomplete. Namely:
156
+
157
+ * What credentails should a user use to login, and how does your application verify it?
158
+ * Once a user has authenticated, how does your application know about that user?
159
+
160
+ The first point is that your application doesn't have to worry about it, since that is the whole point of CAS (and single sign-on).
161
+ Once your CAS server is set up, any application you write and integrate with it won't have to worry about it. Your CAS
162
+ server will take care of it for you.
163
+
164
+ The second point, however,requires some explanation and experimentation...
73
165
 
74
- Various Rails authentication gems makes the currently authenticated user available as an object via the ```current_user``` helper
75
- method. The rack-cas-rails gem does not provide this functionality. But you can look to gems such as
76
- [OmniAuth](https://github.com/intridea/omniauth), [Devise](https://github.com/plataformatec/devise),
77
- [Authlogic](https://github.com/binarylogic/authlogic) and so on to provide it.
166
+ Once a user has authenticated, the [rack-cas](https://github.com/biola/rack-cas) gem will insert some information about
167
+ that user into your application's session for it to retrieve. Your application should then take this information, usually
168
+ in the form of a username, and look up information about that user. Based on the information available, your application can
169
+ then implement additional features such as authorziation (not covered here).
78
170
 
79
- But, assuming your application has a ActiveRecord model named ```User``` where its accmpanying database table containing user records
80
- which are uniquely identifiable by a ```username``` attribute, you can add the following code to your ApplictionController to
81
- provide your application with the ```current_user``` method:
171
+ Ideally, your application should use the same data repository as your CAS server to look up user information. That repository can
172
+ be a SQL database table, some LDAP server, or any number of things. But for now, we can fake it.
173
+
174
+ Go ahead and create a scaffold around a Person model (or any other name you'd like to use), like so:
175
+
176
+ ```
177
+ $ rails generate scaffold person name:string age:integer
178
+ $ rake db:migrate
179
+ ```
180
+
181
+ Populate the ```people``` table with at least one row where the ```name``` column has the same value as one of the users your CAS
182
+ server knows about and you know the password of. For example, let's use "jsmith":
183
+
184
+ ```
185
+ $ rails console
186
+ Loading development environment (Rails 4.2.0)
187
+ 2.2.0 :001 > person = Person.new(name: "jsmith", age: 123)
188
+ => #<Person id: nil, name: "jsmith", age: 123, created_at: nil, updated_at: nil>
189
+ 2.2.0 :002 > person.save!
190
+ (0.2ms) begin transaction
191
+ SQL (33.5ms) INSERT INTO "people" ("name", "age", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["name", "jsmith"],
192
+ ["age", 123], ["created_at", "2015-02-16 02:27:18.121111"], ["updated_at", "2015-02-16 02:27:18.121111"]]
193
+ (1.5ms) commit transaction
194
+ => true
195
+ 2.2.0 :003 > quit
196
+ ```
197
+
198
+ Now, let's add a helper named ```current_user``` (or any other name you like) to your application:
82
199
 
83
200
  ```ruby
84
- class ApplicationController
201
+ # app/controllers/application_ronctoller.rb
85
202
 
86
- # ...
87
-
203
+ require "rack_cas_rails"
204
+ class ApplicationController < ActionController::Base
205
+ # Prevent CSRF attacks by raising an exception.
206
+ # For APIs, you may want to use :null_session instead.
207
+ protect_from_forgery with: :exception
208
+ before_action :authenticate!, except: [:index, :show]
88
209
  def current_user
89
- authenciated? ? User.find_by_login(request.session["cas"]["user"]) : nil
210
+ authenticated? ? Person.find_by_name(request.session["cas"]["user"]) : nil
90
211
  end
91
-
92
212
  helper_method :current_user
93
-
94
213
  end
95
214
  ```
96
215
 
97
- *Note the user records should be the same ones available to CASinoApp for authentication.*
98
-
99
- Lastly, change your ```views/layouts/application.html.erb``` to be as follows:
216
+ Next, change your layout to be as follows:
100
217
 
101
218
  ```erb
219
+ <!-- views/layouts/application.html.erb -->
220
+
102
221
  <!DOCTYPE html>
103
222
  <html>
104
223
  <head>
@@ -108,12 +227,13 @@ Lastly, change your ```views/layouts/application.html.erb``` to be as follows:
108
227
  <%= csrf_meta_tags %>
109
228
  </head>
110
229
  <body>
111
- <divi id="nav-header">
230
+ <div id="header">
112
231
  <% if authenticated? %>
113
- <span>Logged in as <%= current_user.username %>.</span>
232
+ <span>You are logged in as <%= current_user.name %>.</span>
114
233
  <span style="float:right"><%= link_to "Logout", logout_url %></span>
115
234
  <% else %>
116
- <span><%= link_to "Login", login_url %></span>
235
+ <span>You are not logged in.</span>
236
+ <span style="float:right"><%= link_to "Login", login_url %></span>
117
237
  <% end %>
118
238
  </div>
119
239
  <hr />
@@ -124,20 +244,27 @@ Lastly, change your ```views/layouts/application.html.erb``` to be as follows:
124
244
  </html>
125
245
  ```
126
246
 
247
+ Restart your application again, and visit an ```/index``` endpoint. Click the __Login__ link, and authenticate using "jsmith"
248
+ (or whichever user you chose) and the correct password. Once authenticated, you'll be re-directed back to the original page.
249
+ This time, you are shown whom you are logged in as. Now visit a ```/new``` endpoint, and you won't be prompted to authenticate
250
+ again, until you click the __Logout__ link or restart your browser.
251
+
127
252
  ## Summary
128
253
 
129
- To recap, you'll have integrated your Rails application with a CAS-compliant server by making these changes to your application:
254
+ With rack-cas-rails, you can integrate your Rails application with CASinoApp or another CAS-compliant server for
255
+ authentication by making these changes in it:
130
256
 
131
- 1. Add ```config.rack_cas.server_url``` to config/application.rb
132
- 2. Add ```before_action :authenticate!``` to ApplicationController
133
- 3. Add ```current_user``` method to ApplictionController
134
- 4. Add simple navigational header to make use of ```current_user``` and the ```login_url```/```logout_url``` helpers
257
+ 1. Your Rails::Application subclass (in config/application.rb)
258
+ 2. Your ApplicationController class (in app/controllers/application_controller.rb)
259
+ 3. Your layout template (in app/views/layouts/application.html.erb)
260
+ 4. Add a model (or some other means) by which you can retrieve information about the currently logged in user
135
261
 
136
- As such, you can expect the following behavior:
262
+ With these changes in place, you can expect your application to exhibit the following behavior:
137
263
 
138
- * When you browse to any view within your application using a fresh session, you'll be re-directed to the sign-in page
139
- * After you authenticate, you'll be re-directed back to the page you browsed to
140
- * When you click the Logout link, your session will end, and the browser will be re-directed back to the login page
264
+ * When you browse to any protected endpoint within your application using a fresh session, you'll be re-directed to the sign-in page
265
+ * After you authenticate, you'll be re-directed back to the page you browsed to, after which you'll have access to all endpoints
266
+ * When you click the __Logout__ link or restart your browser, your session will end; and should you now attempt to access
267
+ a protected enpoint, you'll be prompted to log in once again
141
268
 
142
269
  ## Credits
143
270
 
@@ -0,0 +1,22 @@
1
+ ##
2
+ # Augments the Rails application class.
3
+
4
+ class Rails::Application < Rails::Engine
5
+
6
+ ##
7
+ # Gives the Rails::Application class a read-only class attribute to point to the CAS server URL. The URL in turn is then
8
+ # settable using @cas_server_url at the class level.
9
+
10
+ class << self
11
+ attr_reader :cas_server_url
12
+ end
13
+
14
+ ##
15
+ # Gets the CAS server root URL. Provides a convenience method at the instance level to fetch it.
16
+ # @return [String] Cas server's root URL.
17
+
18
+ def cas_server_url
19
+ self.class.cas_server_url
20
+ end
21
+
22
+ end
@@ -10,7 +10,12 @@ class ApplicationController < ActionController::Base
10
10
  # When invoked, will force authenticate. Most likely to be invoked as a before_action.
11
11
 
12
12
  def authenticate!
13
- authenticated? or render(:file => "public/401.html", :status => :unauthorized) # HTTP 401
13
+ return if authenticated?
14
+ if File.exists?("public/401.html")
15
+ render(:file => "public/401.html", :status => :unauthorized)
16
+ else
17
+ render(:plain => "Unauthorized!", :status => :unauthorized)
18
+ end
14
19
  end
15
20
 
16
21
  ##
@@ -27,7 +32,7 @@ class ApplicationController < ActionController::Base
27
32
  # @return [String] The CAS login URL.
28
33
 
29
34
  def login_url(service_url=request.url)
30
- url = URI(Rails.application.config.rack_cas.server_url)
35
+ url = URI(Rails.application.cas_server_url)
31
36
  url.path = "/login"
32
37
  url.query = "service=#{service_url || request.url}"
33
38
  url.to_s
@@ -1,3 +1,3 @@
1
1
  module RackCASRails
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -0,0 +1,3 @@
1
+ require "rack_cas_rails/application"
2
+ require "rack_cas_rails/controllers"
3
+ require "rack_cas_rails/version"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-cas-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Brazil
@@ -44,6 +44,48 @@ dependencies:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
46
  version: 4.2.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: byebug
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: sqlite3
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: yard
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
47
89
  description: Provides the integration glue between a Rails application and biola/rack-cas
48
90
  so that a CAS-compliant server (only tested with CASinoApp) can be used for authentication
49
91
  by the application.
@@ -54,9 +96,10 @@ extra_rdoc_files: []
54
96
  files:
55
97
  - LICENSE
56
98
  - README.md
57
- - lib/rack-cas-rails.rb
58
- - lib/rack-cas-rails/controllers.rb
59
- - lib/rack-cas-rails/version.rb
99
+ - lib/rack_cas_rails.rb
100
+ - lib/rack_cas_rails/application.rb
101
+ - lib/rack_cas_rails/controllers.rb
102
+ - lib/rack_cas_rails/version.rb
60
103
  homepage: https://github.com/bitaxis/rack-cas-rails.git
61
104
  licenses:
62
105
  - MIT
@@ -1 +0,0 @@
1
- require "rack-cas-rails/controllers"