snaury-thin-auth-ntlm 0.0.2

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.
data/LICENSE.txt ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Alexey Borzenkov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.txt ADDED
@@ -0,0 +1,11 @@
1
+ = NTLM Authentication for Thin
2
+
3
+ Allows you to force NTLM authentication on Thin TCP servers.
4
+
5
+ = Using thin-auth-ntlm
6
+
7
+ Just start your thin server using NTLMTcpServer backend:
8
+
9
+ thin -r thin-auth-ntlm -b Thin::Backends::NTLMTcpServer start
10
+
11
+ Remote username will be available as request.remote_user.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "thin-auth-ntlm"
5
+ gemspec.summary = "Allows you to force NTLM authentication on Thin TCP servers."
6
+ gemspec.author = "Alexey Borzenkov"
7
+ gemspec.email = "snaury@gmail.com"
8
+
9
+ gemspec.add_dependency('thin', '>= 1.0.0')
10
+ gemspec.add_dependency('rubysspi-server', '>= 0.0.1')
11
+ end
12
+ rescue LoadError
13
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
14
+ end
@@ -0,0 +1,13 @@
1
+ module Thin
2
+ module Backends
3
+ class NTLMTcpServer < TcpServer
4
+ def initialize(host, port, options)
5
+ super(host, port)
6
+ end
7
+
8
+ def connect
9
+ @signature = EventMachine.start_server(@host, @port, NTLMConnection, &method(:initialize_connection))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,128 @@
1
+ require 'win32/sspi/server'
2
+
3
+ module Thin
4
+ class NTLMConnection < Connection
5
+ AUTHORIZATION_MESSAGE = <<END
6
+ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
7
+ <html><head>
8
+ <title>401 NTLM Authorization Required</title>
9
+ </head><body>
10
+ <h1>NTLM Authorization Required</h1>
11
+ <p>This server could not verify that you
12
+ are authorized to access the document
13
+ requested. Either you supplied the wrong
14
+ credentials (e.g., bad password), or your
15
+ browser doesn't understand how to supply
16
+ the credentials required.</p>
17
+ </body></html>
18
+ END
19
+ REMOTE_USER = 'REMOTE_USER'.freeze
20
+ HTTP_AUTHORIZATION = 'HTTP_AUTHORIZATION'.freeze
21
+ WWW_AUTHENTICATE = 'WWW-Authenticate'.freeze
22
+ CONTENT_TYPE = 'Content-Type'.freeze
23
+ CONTENT_TYPE_AUTH = 'text/html; charset=iso-8859-1'.freeze
24
+ NTLM_REQUEST_PACKAGE = 'NTLM'.freeze
25
+ NTLM_ALLOWED_PACKAGE = 'NTLM|Negotiate'.freeze
26
+
27
+ def unbind
28
+ ntlm_cleanup
29
+ ensure
30
+ super
31
+ end
32
+
33
+ def process
34
+ # check if browser wants to reauthenticate
35
+ if @authenticated_as && http_authorization
36
+ @authenticated_as = nil
37
+ end
38
+ # require authentication
39
+ unless @authenticated_as
40
+ unless @authentication_stage
41
+ @post_ntlm_can_persist = @can_persist
42
+ @authentication_stage = 1
43
+ end
44
+ result = ntlm_process
45
+ return post_process(result) unless @authenticated_as
46
+ end
47
+
48
+ @request.env[REMOTE_USER] = @authenticated_as
49
+ @can_persist = @post_ntlm_can_persist
50
+ return super
51
+ end
52
+
53
+ def http_authorization
54
+ auth = @request.env[HTTP_AUTHORIZATION]
55
+ if auth
56
+ auth = auth.strip
57
+ auth = nil if auth.empty?
58
+ end
59
+ auth
60
+ end
61
+
62
+ def ntlm_acquire(package = 'NTLM')
63
+ ntlm_cleanup
64
+ @ntlm = Win32::SSPI::NegotiateServer.new(package)
65
+ @ntlm.acquire_credentials_handle
66
+ @ntlm
67
+ end
68
+
69
+ def ntlm_cleanup
70
+ if @ntlm
71
+ @ntlm.cleanup rescue nil
72
+ @ntlm = nil
73
+ end
74
+ nil
75
+ end
76
+
77
+ def ntlm_token
78
+ auth = http_authorization
79
+ return [nil, nil] unless auth && auth.match(/\A(#{NTLM_ALLOWED_PACKAGE}) (.*)\Z/)
80
+ [$1, Base64.decode64($2.strip)]
81
+ end
82
+
83
+ def ntlm_process
84
+ case @authentication_stage
85
+ when 1 # we are waiting for type1 message
86
+ package, t1 = ntlm_token
87
+ return ntlm_request_auth(NTLM_REQUEST_PACKAGE, false) if t1.nil?
88
+ return ntlm_request_auth unless request.persistent?
89
+ begin
90
+ ntlm_acquire(package)
91
+ t2 = @ntlm.accept_security_context(t1)
92
+ rescue
93
+ return ntlm_request_auth
94
+ end
95
+ ntlm_request_auth("#{package} #{t2}", false, 2)
96
+ when 2 # we are waiting for type3 message
97
+ package, t3 = ntlm_token
98
+ return ntlm_request_auth(NTLM_REQUEST_PACKAGE, false) if t3.nil?
99
+ return ntlm_request_auth unless package == @ntlm.package
100
+ return ntlm_request_auth unless request.persistent?
101
+ begin
102
+ t2 = @ntlm.accept_security_context(t3)
103
+ @authenticated_as = @ntlm.get_username_from_context
104
+ @authentication_stage = 1 # in case IE8 wants to reauthenticate
105
+ rescue
106
+ return ntlm_request_auth
107
+ end
108
+ return ntlm_request_auth unless @authenticated_as
109
+ ntlm_cleanup
110
+ else
111
+ raise "Invalid value for @authentication_stage=#{@authentication_stage} detected"
112
+ end
113
+ rescue Exception
114
+ handle_error
115
+ terminate_request
116
+ nil
117
+ end
118
+
119
+ def ntlm_request_auth(auth = nil, finished = true, next_stage = 1)
120
+ @authentication_stage = next_stage
121
+ @can_persist = !finished
122
+ head = {}
123
+ head[WWW_AUTHENTICATE] = auth if auth
124
+ head[CONTENT_TYPE] = CONTENT_TYPE_AUTH
125
+ return [401, head, [AUTHORIZATION_MESSAGE]]
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,9 @@
1
+ require 'thin'
2
+
3
+ module Thin
4
+ autoload :NTLMConnection, 'thin/ntlm/connection'
5
+
6
+ module Backends
7
+ autoload :NTLMTcpServer, 'thin/ntlm/backends/tcp_server'
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snaury-thin-auth-ntlm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexey Borzenkov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-18 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thin
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rubysspi-server
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.1
34
+ version:
35
+ description:
36
+ email: snaury@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE.txt
43
+ - README.txt
44
+ files:
45
+ - LICENSE.txt
46
+ - README.txt
47
+ - Rakefile
48
+ - lib/thin-auth-ntlm.rb
49
+ - lib/thin/ntlm/backends/tcp_server.rb
50
+ - lib/thin/ntlm/connection.rb
51
+ has_rdoc: true
52
+ homepage:
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.2.0
74
+ signing_key:
75
+ specification_version: 2
76
+ summary: Allows you to force NTLM authentication on Thin TCP servers.
77
+ test_files: []
78
+