nitro-auth 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,12 @@
1
+ <b>0.2.0</b> (2005-07-26)
2
+
3
+ * Updated for Nitro 0.21.0.
4
+ * Moved paths into 'nitro/auth' instead of just 'auth'.
5
+ * Fixes for overriding Auth::User with an application version.
6
+ * Got the basic example working.
7
+ * Fixed a bug in access_denied.xhtml.
8
+ * Actually got the license details set up.
9
+
10
+ <b>0.1.0</b> (2005-07-21)
11
+
12
+ * Initial implementation of nitro-auth. Lots still to do.
data/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+ The BSD License
2
+
3
+ Copyright (c) 2005, Deborah 'Ysabel' Hooker
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are
8
+ met:
9
+
10
+ * Redistributions of source code must retain the above copyright
11
+ notice, this list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright
14
+ notice, this list of conditions and the following disclaimer in the
15
+ documentation and/or other materials provided with the distribution.
16
+
17
+ * Ms. Hooker's name may not be used to endorse or promote products
18
+ derived from this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26
+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+
data/README ADDED
@@ -0,0 +1,115 @@
1
+ = nitro-auth: Authentication and Authorization for Nitro
2
+
3
+ nitro-auth provides basic forms-based authentication and role-based
4
+ authorization for applications built on the
5
+ Nitro[http://www.nitrohq.com/] web engine. It is designed
6
+ to allow easy integration with an application, including declarative
7
+ authorization rules and easy application-specific rendering of auth-related
8
+ pages.
9
+
10
+ nitro-auth is currently version 0.2.0 and is, as you might expect, far
11
+ from feature-complete. But even so, it hopefully has enough to get you
12
+ started.
13
+
14
+ == Features
15
+
16
+ * Persistent Auth::User and Auth::Role objects. nitro-auth only declares
17
+ the minimum fields necessary for doing authentication (fields like +login+,
18
+ +password+ and +session_key+) and lets the application extend them further.
19
+
20
+ * Auth::Controller mixin which provides authentication information and
21
+ declarative role-based security to Nitro controllers::
22
+
23
+ require 'nitro'
24
+ require 'nitro/auth'
25
+
26
+ class MyController < Nitro::Controller
27
+ include Auth::Controller
28
+
29
+ def list_details
30
+ [...]
31
+ end
32
+ protect :list_details
33
+
34
+ def edit_details
35
+ [...]
36
+ end
37
+ required_role :edit_details, :manager
38
+
39
+ def edit_user
40
+ [...]
41
+ end
42
+ administrative :edit_user
43
+ end
44
+
45
+ * Passwords are stored in a salted, hashed form using SHA1 hashes.
46
+
47
+ * Cookie-based login session persistence.
48
+
49
+ * Authentication controller uses Nitro templates for easy application
50
+ integration.
51
+
52
+ == Coming soon
53
+
54
+ * Challenge-response authentication, including JavaScript client-side
55
+ challenge-response validation.
56
+
57
+ == Download
58
+
59
+ See the Nitro Rubyforge Page (http://rubyforge.org/projects/nitro) for
60
+ the latest nitro-auth package.
61
+
62
+ == Documentation
63
+
64
+ (TODO: Get the rdoc up, probably at http://nitrohq.com/rdoc/nitro-auth)
65
+ In the meantime, you can see it at http://www.ysabel.org/ruby/doc/nitro-auth
66
+ if you'd like to browse.
67
+
68
+ == Requirements
69
+
70
+ nitro-auth requires Nitro, of course. See NitroHQ[http://www.nitrohq.com/]
71
+ (http://www.nitrohq.com) for current releases
72
+ of Nitro.
73
+
74
+ [Ruby 1.8.1 and greater]
75
+ http://www.ruby-lang.org
76
+ (Version 1.8.2 is recomended)
77
+
78
+ == Installation
79
+
80
+ = rubygem install (simplest, recommended):
81
+
82
+ <tt>> gem install nitro-auth</tt>
83
+
84
+ = zip/tgz install
85
+
86
+ Unzip/untar and make sure the lib directory is in your path.
87
+ (Use the gem, trust me, it's easier.)
88
+
89
+ == Contents
90
+
91
+ [examples/]
92
+ Examples of using nitro-auth. (Well, really, example right now.)
93
+
94
+ [lib/]
95
+ nitro-auth library source files.
96
+
97
+ [test/]
98
+ nitro-auth tests.
99
+
100
+ == Support
101
+
102
+ The Nitro mailing list is nitro-general@rubyforge.org, and is a good place
103
+ to start. You can subscribe and/or browse archives at
104
+ http://rubyforge.org/mailman/listinfo/nitro-general
105
+
106
+ You may also drop the author an email at mailto:deb@ysabel.org.
107
+
108
+ TBD: Bug/feature request tracking
109
+
110
+ == License
111
+
112
+ Copyright (c) 2005, Deborah 'Ysabel' Hooker
113
+
114
+ nitro-auth is copyrighted free software released under the BSD license.
115
+ For details consult the LICENSE file.
data/TODO ADDED
@@ -0,0 +1,7 @@
1
+ = nitro-auth To Do List
2
+
3
+ * Challenge-response authentication.
4
+ * Examples.
5
+ * Tests. (Testing Nitro controllers?)
6
+ * Extension via relation as well as inheritance.
7
+ * FIXMEs.
@@ -0,0 +1,81 @@
1
+ <html>
2
+ <head>
3
+ <title>Error</title>
4
+ <style>
5
+ .path {
6
+ padding: 5px;
7
+ font-size: 140%;
8
+ background: #ddd;
9
+ }
10
+ .error {
11
+ padding: 5px;
12
+ padding-top: 15px;
13
+ font-size: 140%;
14
+ color: #f00;
15
+ }
16
+ .load {
17
+ padding: 5px;
18
+ color: #555;
19
+ }
20
+ .source {
21
+ border: 1px solid #ccc;
22
+ padding: 10px;
23
+ margin-top: 10px; margin-bottom: 10px;
24
+ }
25
+ h2 {
26
+ padding-left: 5px;
27
+ background: #eee;
28
+ }
29
+ </style>
30
+ </head>
31
+ <body>
32
+ <h1>Error</h1>
33
+
34
+ <?r for error, path in @context.rendering_errors ?>
35
+ <div class="path"><strong>Path:</strong> #{path}</div>
36
+ <div class="error"><strong>#{error.to_s}</strong></div>
37
+ <div class="load">Click here to <strong><a href="#{request.uri}">reload</a></strong>.</div>
38
+ <div class="load">Click here to go to the <strong><a href="#{request.referer}">referer</a></strong> or the <strong><a href="/">home page</a></strong>.</div>
39
+ <?r if error.respond_to?(:source_extract) ?>
40
+ <div class="source">
41
+ <?r
42
+ extract = error.source_extract.split("\n")
43
+ extract.each_with_index do |line, idx|
44
+ line = Nitro::Markup.expand(line)
45
+ if 4 == idx
46
+ ?>
47
+ <div style="background: #eee">#{line}</div>
48
+ <?r else ?>
49
+ <div>#{line}</div>
50
+ <?r
51
+ end
52
+ end
53
+ ?>
54
+ </div>
55
+ <?r end ?>
56
+ <h2><a href="#" onclick="document.getElementById('trace').style.display = 'block'; return false">Stack Trace</a></h2>
57
+ <p id="trace" style="display: none">#{error.backtrace.join('<br />')}</p>
58
+ <?r end ?>
59
+
60
+ <h2><a href="#" onclick="document.getElementById('request').style.display = 'block'; return false">Request</a></h2>
61
+ <div id="request" style="display: none">
62
+ <p><strong>Parameters:</strong> #{request.params.reject{ |k,v| k == :__RELOADED__ }.inspect}</p>
63
+ <p><strong>Cookies:</strong> #{request.cookies.inspect}</p>
64
+ <p><strong>Headers:</strong><br />#{request.headers.collect { |k, v| "#{k} => #{v}" }.join('<br />')}</p>
65
+ </div>
66
+
67
+ <h2><a href="#" onclick="document.getElementById('response').style.display = 'block'; return false">Response</a></h2>
68
+ <div id="response" style="display: none">
69
+ <p><strong>Headers:</strong> #{request.response_headers.inspect}</p>
70
+ <p><strong>Cookies:</strong> #{request.response_cookies.inspect}</p>
71
+ </div>
72
+
73
+ <h2><a href="#" onclick="document.getElementById('session').style.display = 'block'; return false">Session</a></h2>
74
+ <div id="session" style="display: none">
75
+ <p><strong>Values:</strong> #{session.inspect}</p>
76
+ </div>
77
+
78
+ <br /><br />
79
+ Powered by <a href="http://www.nitrohq.com">Nitro</a> version #{Nitro::Version}
80
+ </body>
81
+ </html>
@@ -0,0 +1,254 @@
1
+ /*
2
+ Behaviour v1.0 by Ben Nolan, June 2005. Based largely on the work
3
+ of Simon Willison (see comments by Simon below).
4
+
5
+ Description:
6
+
7
+ Uses css selectors to apply javascript behaviours to enable
8
+ unobtrusive javascript in html documents.
9
+
10
+ Usage:
11
+
12
+ var myrules = {
13
+ 'b.someclass' : function(element){
14
+ element.onclick = function(){
15
+ alert(this.innerHTML);
16
+ }
17
+ },
18
+ '#someid u' : function(element){
19
+ element.onmouseover = function(){
20
+ this.innerHTML = "BLAH!";
21
+ }
22
+ }
23
+ );
24
+
25
+ Behaviour.register(myrules);
26
+
27
+ // Call Behaviour.apply() to re-apply the rules (if you
28
+ // update the dom, etc).
29
+
30
+ License:
31
+
32
+ My stuff is BSD licensed. Not sure about Simon's.
33
+
34
+ More information:
35
+
36
+ http://ripcord.co.nz/behaviour/
37
+
38
+ */
39
+
40
+ var Behaviour = {
41
+ list : new Array,
42
+
43
+ register : function(sheet){
44
+ Behaviour.list.push(sheet);
45
+ },
46
+
47
+ start : function(){
48
+ Behaviour.addLoadEvent(function(){
49
+ Behaviour.apply();
50
+ });
51
+ },
52
+
53
+ apply : function(){
54
+ for (h=0;sheet=Behaviour.list[h];h++){
55
+ for (selector in sheet){
56
+ list = document.getElementsBySelector(selector);
57
+
58
+ if (!list){
59
+ continue;
60
+ }
61
+
62
+ for (i=0;element=list[i];i++){
63
+ sheet[selector](element);
64
+ }
65
+ }
66
+ }
67
+ },
68
+
69
+ addLoadEvent : function(func){
70
+ var oldonload = window.onload;
71
+
72
+ if (typeof window.onload != 'function') {
73
+ window.onload = func;
74
+ } else {
75
+ window.onload = function() {
76
+ oldonload();
77
+ func();
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ Behaviour.start();
84
+
85
+ /*
86
+ The following code is Copyright (C) Simon Willison 2004.
87
+
88
+ document.getElementsBySelector(selector)
89
+ - returns an array of element objects from the current document
90
+ matching the CSS selector. Selectors can contain element names,
91
+ class names and ids and can be nested. For example:
92
+
93
+ elements = document.getElementsBySelect('div#main p a.external')
94
+
95
+ Will return an array of all 'a' elements with 'external' in their
96
+ class attribute that are contained inside 'p' elements that are
97
+ contained inside the 'div' element which has id="main"
98
+
99
+ New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
100
+ See http://www.w3.org/TR/css3-selectors/#attribute-selectors
101
+
102
+ Version 0.4 - Simon Willison, March 25th 2003
103
+ -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
104
+ -- Opera 7 fails
105
+ */
106
+
107
+ function getAllChildren(e) {
108
+ // Returns all children of element. Workaround required for IE5/Windows. Ugh.
109
+ return e.all ? e.all : e.getElementsByTagName('*');
110
+ }
111
+
112
+ document.getElementsBySelector = function(selector) {
113
+ // Attempt to fail gracefully in lesser browsers
114
+ if (!document.getElementsByTagName) {
115
+ return new Array();
116
+ }
117
+ // Split selector in to tokens
118
+ var tokens = selector.split(' ');
119
+ var currentContext = new Array(document);
120
+ for (var i = 0; i < tokens.length; i++) {
121
+ token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
122
+ if (token.indexOf('#') > -1) {
123
+ // Token is an ID selector
124
+ var bits = token.split('#');
125
+ var tagName = bits[0];
126
+ var id = bits[1];
127
+ var element = document.getElementById(id);
128
+ if (tagName && element.nodeName.toLowerCase() != tagName) {
129
+ // tag with that ID not found, return false
130
+ return new Array();
131
+ }
132
+ // Set currentContext to contain just this element
133
+ currentContext = new Array(element);
134
+ continue; // Skip to next token
135
+ }
136
+ if (token.indexOf('.') > -1) {
137
+ // Token contains a class selector
138
+ var bits = token.split('.');
139
+ var tagName = bits[0];
140
+ var className = bits[1];
141
+ if (!tagName) {
142
+ tagName = '*';
143
+ }
144
+ // Get elements matching tag, filter them for class selector
145
+ var found = new Array;
146
+ var foundCount = 0;
147
+ for (var h = 0; h < currentContext.length; h++) {
148
+ var elements;
149
+ if (tagName == '*') {
150
+ elements = getAllChildren(currentContext[h]);
151
+ } else {
152
+ elements = currentContext[h].getElementsByTagName(tagName);
153
+ }
154
+ for (var j = 0; j < elements.length; j++) {
155
+ found[foundCount++] = elements[j];
156
+ }
157
+ }
158
+ currentContext = new Array;
159
+ var currentContextIndex = 0;
160
+ for (var k = 0; k < found.length; k++) {
161
+ if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
162
+ currentContext[currentContextIndex++] = found[k];
163
+ }
164
+ }
165
+ continue; // Skip to next token
166
+ }
167
+ // Code to deal with attribute selectors
168
+ if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
169
+ var tagName = RegExp.$1;
170
+ var attrName = RegExp.$2;
171
+ var attrOperator = RegExp.$3;
172
+ var attrValue = RegExp.$4;
173
+ if (!tagName) {
174
+ tagName = '*';
175
+ }
176
+ // Grab all of the tagName elements within current context
177
+ var found = new Array;
178
+ var foundCount = 0;
179
+ for (var h = 0; h < currentContext.length; h++) {
180
+ var elements;
181
+ if (tagName == '*') {
182
+ elements = getAllChildren(currentContext[h]);
183
+ } else {
184
+ elements = currentContext[h].getElementsByTagName(tagName);
185
+ }
186
+ for (var j = 0; j < elements.length; j++) {
187
+ found[foundCount++] = elements[j];
188
+ }
189
+ }
190
+ currentContext = new Array;
191
+ var currentContextIndex = 0;
192
+ var checkFunction; // This function will be used to filter the elements
193
+ switch (attrOperator) {
194
+ case '=': // Equality
195
+ checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
196
+ break;
197
+ case '~': // Match one of space seperated words
198
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
199
+ break;
200
+ case '|': // Match start with value followed by optional hyphen
201
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
202
+ break;
203
+ case '^': // Match starts with value
204
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
205
+ break;
206
+ case '$': // Match ends with value - fails with "Warning" in Opera 7
207
+ checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
208
+ break;
209
+ case '*': // Match ends with value
210
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
211
+ break;
212
+ default :
213
+ // Just test for existence of attribute
214
+ checkFunction = function(e) { return e.getAttribute(attrName); };
215
+ }
216
+ currentContext = new Array;
217
+ var currentContextIndex = 0;
218
+ for (var k = 0; k < found.length; k++) {
219
+ if (checkFunction(found[k])) {
220
+ currentContext[currentContextIndex++] = found[k];
221
+ }
222
+ }
223
+ // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
224
+ continue; // Skip to next token
225
+ }
226
+
227
+ if (!currentContext[0]){
228
+ return;
229
+ }
230
+
231
+ // If we get here, token is JUST an element (not a class or ID selector)
232
+ tagName = token;
233
+ var found = new Array;
234
+ var foundCount = 0;
235
+ for (var h = 0; h < currentContext.length; h++) {
236
+ var elements = currentContext[h].getElementsByTagName(tagName);
237
+ for (var j = 0; j < elements.length; j++) {
238
+ found[foundCount++] = elements[j];
239
+ }
240
+ }
241
+ currentContext = found;
242
+ }
243
+ return currentContext;
244
+ }
245
+
246
+ /* That revolting regular expression explained
247
+ /^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
248
+ \---/ \---/\-------------/ \-------/
249
+ | | | |
250
+ | | | The value
251
+ | | ~,|,^,$,* or =
252
+ | Attribute
253
+ Tag
254
+ */