wikk_web_auth 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ecd4829760efaf1668d18a19881a30066d68a6c0
4
+ data.tar.gz: a9c80865749876369330677d7fdad881ac8376eb
5
+ SHA512:
6
+ metadata.gz: 6bcb14d568d41c9467dc5a844469f31115b28c09d9743ced5d9c856f61a0976e82f2b5dc07fc5cf4c36812f7a002450158068ca27b8ce7b88cec611b6fb3ec02
7
+ data.tar.gz: 726c057193a25b2cebc441853fd833ed2ef9be6c7075577c56110c9cd48cf46bc25437932487e60fcdb53da880c4989a042b2d3a5cdfef2441fd7bc6ca7870b7
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2016-06-19
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,5 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/wikk_web_auth.rb
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # wikk_web_auth
2
+
3
+ * http://wikarekare.github.com/wikk_web_auth/
4
+ * Source https://github.com/wikarekare/wikk_web_auth
5
+ * Gem https://rubygems.org/gems/wikk_web_auth
6
+
7
+ ## DESCRIPTION:
8
+
9
+ Gem provides common authentication framework for Wikarekare's Ruby CGIs.
10
+
11
+ ## FEATURES/PROBLEMS:
12
+
13
+ * In process of conversion from a library to a gem, and refactored to be more generic. Needs some real world testing.
14
+
15
+ ## SYNOPSIS:
16
+
17
+ ### Redirect to login scenario
18
+ * Logic flows from clients to the cgi;
19
+ * generating a login html page;
20
+ * client logs in, sending the form to the login.rbx Ruby cgi;
21
+ * If successful, the login.rbx cgi sends back a redirect to the original cgi.
22
+
23
+ ### Javascript Scenario, with separation of function.
24
+ * A separate login button is included on the HTML page, which uses the wikk_auth_js library
25
+ ```
26
+ <html>
27
+ <head>
28
+ <script src="wikk_web_auth.js"></script>
29
+ ...
30
+ <script>
31
+ init() {
32
+ //Check if we are authenticated, and fill in login span appropriately.
33
+ logged_in(true, '/admin/sites.html'); //(display lock/unlock image, return url after login page)
34
+ ...
35
+ }
36
+ ...
37
+ </script>
38
+ </head>
39
+ <body onload="init();">
40
+ ...
41
+ <span id="login_span"></span>
42
+ ...
43
+ ```
44
+ * The cgi simple calls the class level WIKK::Web_Auth.authenticate? call, for a true/false response.
45
+ ```
46
+ require 'wikk_web_auth'
47
+ @authenticated = Authenticated.authenticated?(@cgi)
48
+ ```
49
+
50
+ ## REQUIREMENTS:
51
+
52
+ * Used in conjunction with Ruby cgi login.rbx
53
+ * relies on gems wikk_password
54
+ * Could make use of wikk_configuration and wikk_aes_256
55
+
56
+ ## INSTALL:
57
+
58
+ * sudo gem install wikk_web_auth
59
+
60
+ ## LICENSE:
61
+
62
+ (The MIT License)
63
+
64
+ Derived from Wikarekare authentication.rb library.
65
+
66
+ Copyright (c) 2004-2016
67
+
68
+ Permission is hereby granted, free of charge, to any person obtaining
69
+ a copy of this software and associated documentation files (the
70
+ 'Software'), to deal in the Software without restriction, including
71
+ without limitation the rights to use, copy, modify, merge, publish,
72
+ distribute, sublicense, and/or sell copies of the Software, and to
73
+ permit persons to whom the Software is furnished to do so, subject to
74
+ the following conditions:
75
+
76
+ The above copyright notice and this permission notice shall be
77
+ included in all copies or substantial portions of the Software.
78
+
79
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
80
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
81
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
82
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
83
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
84
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
85
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ Hoe.plugin :yard
6
+
7
+ Hoe.spec 'wikk_web_auth' do
8
+ self.readme_file = "README.md"
9
+ self.developer( "Rob Burrowes","r.burrowes@auckland.ac.nz")
10
+ remote_rdoc_dir = '' # Release to root
11
+
12
+ self.yard_title = 'wikk_web_auth'
13
+ self.yard_options = ['--markup', 'markdown', '--protected']
14
+ end
15
+
16
+
17
+ #Validate manfest.txt
18
+ #rake check_manifest
19
+
20
+ #Local checking. Creates pkg/
21
+ #rake gem
22
+
23
+ #create doc/
24
+ #rake docs
25
+
26
+ #Copy up to rubygem.org
27
+ #rake release VERSION=1.0.1
@@ -0,0 +1,263 @@
1
+ module WIKK
2
+ require 'cgi'
3
+ require 'cgi/session'
4
+ require 'cgi/session/pstore' # provides CGI::Session::PStore
5
+ require 'digest/sha2'
6
+ require 'syslog/logger'
7
+ require "wikk_aes_256"
8
+ require 'wikk_password'
9
+
10
+ #Provides common authentication mechanism for all our cgis.
11
+ # @attr_reader [String] user , the remote user's user name
12
+ # @attr_reader [String] session , the persistent Session record for this user
13
+ class Web_Auth
14
+ VERSION = "0.1.0" #Gem version
15
+
16
+ attr_reader :user, :session
17
+
18
+ #Create new Web_Auth instance, and proceed through authentication process by creating a login web form, if the user isn't authenticated.
19
+ # @param cgi [CGI] Which carries the client data, cookies, and PUT/POST form data.
20
+ # @param config [WIKK::Configuration|Hash] the location of the password file is embedded here.
21
+ # @param return_url [String] If we successfully authenticate, return here.
22
+ # @return [WIKK::Web_Auth]
23
+ def initialize(cgi, config, return_url = nil)
24
+ if config.class == Hash
25
+ sym = config.each_with_object({}) { |(k,v),h| h[k.to_sym] = v }
26
+ @config = Struct.new(*(k = sym.keys)).new(*sym.values_at(*k))
27
+ else
28
+ @config = config
29
+ end
30
+ @cgi = cgi
31
+ @user = ''
32
+ @session = nil
33
+ begin
34
+ @log = Syslog::Logger.syslog
35
+ rescue
36
+ @log = Syslog::Logger.new("authlib.rbx")
37
+ end
38
+ authenticate(return_url)
39
+ end
40
+
41
+ #way of checking without doing a full login sequence.
42
+ # @param cgi [CGI] Which carries the client data, cookies, and PUT/POST form data.
43
+ # @return [Boolean] authenticated == true.
44
+ def self.authenticated?(cgi)
45
+ begin
46
+ session = CGI::Session.new(cgi, Web_Auth.session_config({'new_session' => false}) )
47
+ authenticated = (session != nil && session['session_expires'] > Time.now && session['auth'] == true && session['ip'] == cgi.remote_addr)
48
+ session.close #Writes back the session data
49
+ return authenticated
50
+ rescue ArgumentError => error # if no old session to find.
51
+ begin
52
+ @log = Syslog::Logger.syslog
53
+ rescue
54
+ @log = Syslog::Logger.new("authlib.rbx")
55
+ end
56
+ @log.error(error.message)
57
+ return false
58
+ end
59
+ end
60
+
61
+ #get the session reference and delete the session.
62
+ # @param cgi [CGI] Which carries the client data, cookies, and PUT/POST form data.
63
+ def self.logout(cgi)
64
+ begin
65
+ session = CGI::Session.new(cgi, Web_Auth.session_config({'new_session' => false}))
66
+ session.delete if session != nil
67
+ rescue ArgumentError => error # if no old session
68
+ begin
69
+ @log = Syslog::Logger.syslog
70
+ rescue
71
+ @log = Syslog::Logger.new("authlib.rbx")
72
+ end
73
+ @log.error(error.message)
74
+ end
75
+ end
76
+
77
+ #Checks password file to see if the response from the user matches generating a hash from the password locally.
78
+ # @param user [String] Who the remote user claims to be
79
+ # @param challenge [String] Random string we sent to this user, and they used in hashing their password.
80
+ # @param received_hash [String] The hex_SHA256(password + challenge) string that the user sent back.
81
+ # @return [Boolean] True for authorization test suceeded.
82
+ def authorized?(user, challenge, received_hash)
83
+ begin
84
+ return WIKK::Password.valid_sha256_response?(user, @config, challenge, received_hash)
85
+ rescue IndexError => error #User didn't exist
86
+ @log.err("authorized?(#{user}): " + error.message)
87
+ return false
88
+ rescue Exception => error #Something else
89
+ @log.err("authorized?(#{user}): " + error.message)
90
+ return false
91
+ end
92
+ end
93
+
94
+ #Generate the new Session's config parameters, mixing in and/or overriding the preset values.
95
+ # @param extra_arguments [Hash] Extra arguments that get added to the hash, or override values with the same key.
96
+ # @return [Hash] The configuration hash.
97
+ def self.session_config(extra_arguments = {})
98
+ return {
99
+ 'database_manager' => CGI::Session::PStore, # use PStore
100
+ 'session_key' => '_wikk_rb_sess_id', # custom session key
101
+ #'session_id' => ?,
102
+ 'session_expires' => (Time.now + 86400), # 1 day timeout
103
+ 'prefix' => 'pstore_sid_', # PStore option
104
+ 'tmpdir' => '/tmp', # PStore option
105
+ #new_session => ?,#boolean
106
+ #no_hidden => ?,
107
+ #session_domain => ?,
108
+ #session_secure => ?,
109
+ #session_path => ?,
110
+ #no_cookies => ?, #boolean
111
+ #suffix => ?
112
+ }.merge(extra_arguments)
113
+ end
114
+
115
+ def session_state_init(session_options = {})
116
+ session_options.each { |k,v| @session[k] = v }
117
+ end
118
+
119
+ #Test to see if we are already authenticated, and if not, generate an HTML login page.
120
+ # @param return_url [String] We return here if we sucessfully login
121
+ def authenticate(return_url = nil)
122
+ begin
123
+ @session = CGI::Session.new(@cgi, Web_Auth.session_config({'new_session' => false})) #Look for existing session.
124
+ return gen_html_login_page(return_url) if @session == nil
125
+ rescue ArgumentError => error # if no old session
126
+ return gen_html_login_page(return_url)
127
+ rescue Exception => error
128
+ raise Exception, "Authenticate, CGI::Session.new " + error.message
129
+ end
130
+
131
+ @session['auth'] = false if @session['session_expires'] < Time.now || #Session has expired
132
+ @session['ip'] != @cgi.remote_addr || #Not coming from same IP address
133
+ CGI::escapeHTML(@cgi['logout']) != '' #Are trying to logout
134
+
135
+ return if(@session['auth'] == true) #if this is true, then we have already authenticated this session.
136
+
137
+ if (challenge = @session['seed']) != '' #see if we are looking at a login response.
138
+ @user = CGI::escapeHTML(@cgi['Username'])
139
+ response = CGI::escapeHTML(@cgi['Response'])
140
+ if @user != '' && response != '' && authorized?(@user, challenge, response)
141
+ @session['auth'] = true #Response valid.
142
+ @session['user'] = @user
143
+ @session['ip'] = @cgi.remote_addr
144
+ @session['seed'] = '' #Don't use the same one twice.
145
+ @session.close
146
+ return
147
+ end
148
+ end
149
+
150
+ @session.delete #Start a new session.
151
+ gen_html_login_page(return_url)
152
+ @session.close if @session != nil #Saves the session state.
153
+ end
154
+
155
+ #clean up the session, setting @authenticated to false and deleting the session state.
156
+ def logout
157
+ @session.delete if @session != nil
158
+ end
159
+
160
+ #Test to see if user authenticated,
161
+ # @return [Boolean] i.e @authenticated's value.
162
+ def authenticated?
163
+ @session != nil && @session['session_expires'] > Time.now && @session['auth'] == true && session['ip'] == @cgi.remote_addr
164
+ end
165
+
166
+
167
+ #Used by calling cgi to generate a standard login page
168
+ # @param return_url [String] We return here if we sucessfully login
169
+ def gen_html_login_page(return_url = nil)
170
+ session_options = Web_Auth.session_config()
171
+ @session = CGI::Session.new(@cgi, session_options) #Start a new session for future authentications.
172
+ raise "gen_html_login_page: @session == nil" if @session == nil
173
+ challenge = WIKK::AES_256.gen_key_to_s
174
+ session_state_init('auth' => false, 'seed' => challenge, 'ip' => "10.2.2.193", 'session_expires' => session_options['session_expires'])
175
+ @cgi.header("type"=>"text/html")
176
+ @cgi.out do
177
+ @cgi.html do
178
+ @cgi.head{ @cgi.title{"login"} + html_nocache + html_script() } +
179
+ @cgi.body { html_login_form(user, challenge, return_url) + "\n" }
180
+ end
181
+ end
182
+ @session.update
183
+ end
184
+
185
+ #Used by calling cgi to inject a return URL into the html response.
186
+ #Called by calling cgi, when constructing their html headers.
187
+ # @param url [String] URL to redirect to.
188
+ # @return [String] The HTML meta header, or "", if url is empty.
189
+ def html_reload(url = nil)
190
+ if url != nil && url != ''
191
+ "<meta http-equiv=\"Refresh\" content=\"0; URL=#{url}\">\n"
192
+ else
193
+ ""
194
+ end
195
+ end
196
+
197
+ #Used by calling cgi to generate logout with this form.
198
+ # @param cgi_dir [String] directory holding the login.rbx cgi.
199
+ # @return [String] Html logout form.
200
+ def html_logout_form(cgi_dir)
201
+ <<-EOHTMLF2
202
+ <form NAME="login" ACTION="#{cgi_dir}/login.rbx" METHOD="post">
203
+ <input TYPE="submit" NAME="logout" VALUE="logout" >
204
+ </form>
205
+ EOHTMLF2
206
+ end
207
+
208
+ private
209
+ #Login form javascript helper to SHA256 Hash a password and the challenge string sent by the server.
210
+ # @return [String] Javascript to embed in html response.
211
+ def html_script
212
+ <<-EOHTML
213
+ <script type="text/javascript" src="/js/sha256.js"></script>
214
+
215
+ <script language="JavaScript">
216
+ function sendhash() {
217
+ str = document.login.Password.value +
218
+ document.login.Challenge.value;
219
+
220
+ document.login.Response.value = hex_sha256(str);
221
+ document.login.Password.value = "";
222
+ document.login.Challenge.value = "";
223
+ document.login.submit();
224
+ }
225
+ </script>
226
+ EOHTML
227
+ end
228
+
229
+ #Generate html login form.
230
+ # @param user [String] user's login name.
231
+ # @param challenge [String] Random bytes to add to password, before sending back to server.
232
+ # @param return_url [String] Pass the url we want to return to if the login succeeds.
233
+ # @return [String] Login form to embed in html response to user.
234
+ def html_login_form(user, challenge, return_url='')
235
+ <<-EOHTMLF
236
+ <form NAME="login" ACTION="/ruby/login.rbx" METHOD="post">
237
+ <input TYPE="hidden" NAME="Challenge" VALUE="#{challenge}">
238
+ <input TYPE="hidden" NAME="Response" VALUE="">
239
+ <input TYPE="hidden" NAME="ReturnURL" VALUE="#{return_url}">
240
+ <table>
241
+ <tr><th>User name</th><td><input TYPE="text" NAME="Username" VALUE="#{user}" SIZE="32" MAXLENGTH="32"></td></tr>
242
+ <tr><th>Password</th><td><input TYPE="password" NAME="Password" VALUE="" SIZE="32" MAXLENGTH="32"></td></tr>
243
+ <tr><td>&nbsp;</td><td>
244
+ <input ONCLICK="sendhash(); return false;" TYPE="Submit" NAME="submit" VALUE="Submit">
245
+ <input TYPE="button" NAME="Cancel" VALUE=" Cancel "
246
+ ONCLICK="document.login.Username.value='';document.login.Password.value=''">
247
+ </td></tr>
248
+ </table>
249
+ </form>
250
+ <script LANGUAGE="javascript" TYPE="text/javascript">
251
+ document.login.Username.focus();
252
+ </script>
253
+ EOHTMLF
254
+ end
255
+
256
+ #Generate no cache metadata header record.
257
+ # @return [String] Html no-cache meta tag
258
+ def html_nocache
259
+ "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
260
+ end
261
+ end
262
+ end
263
+
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wikk_web_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Burrowes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hoe-yard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.2
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: hoe
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.15'
41
+ description: Gem provides common authentication framework for Wikarekare's Ruby CGIs.
42
+ email:
43
+ - r.burrowes@auckland.ac.nz
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.md
50
+ files:
51
+ - History.txt
52
+ - Manifest.txt
53
+ - README.md
54
+ - Rakefile
55
+ - lib/wikk_web_auth.rb
56
+ homepage: http://wikarekare.github.com/wikk_web_auth/
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options:
62
+ - "--markup"
63
+ - markdown
64
+ - "--protected"
65
+ - "--title"
66
+ - wikk_web_auth
67
+ - "--quiet"
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.5.1
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Gem provides common authentication framework for Wikarekare's Ruby CGIs.
86
+ test_files: []