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 +18 -0
- data/README.txt +11 -0
- data/Rakefile +14 -0
- data/lib/thin/ntlm/backends/tcp_server.rb +13 -0
- data/lib/thin/ntlm/connection.rb +128 -0
- data/lib/thin-auth-ntlm.rb +9 -0
- metadata +78 -0
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
|
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
|
+
|