snaury-thin-auth-ntlm 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.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 3
@@ -1,7 +1,8 @@
1
+ require 'weakref'
1
2
  require 'win32/sspi/server'
2
3
 
3
4
  module Thin
4
- class NTLMConnection < Connection
5
+ class NTLMWrapper
5
6
  AUTHORIZATION_MESSAGE = <<END
6
7
  <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
7
8
  <html><head>
@@ -24,34 +25,38 @@ END
24
25
  NTLM_REQUEST_PACKAGE = 'NTLM'.freeze
25
26
  NTLM_ALLOWED_PACKAGE = 'NTLM|Negotiate'.freeze
26
27
 
27
- def unbind
28
- ntlm_cleanup
29
- ensure
30
- super
28
+ def initialize(app, connection)
29
+ @app = app
30
+ @connection = WeakRef.new(connection)
31
31
  end
32
32
 
33
- def process
33
+ def deferred?(env)
34
+ @app.respond_to?(:deferred?) && @app.deferred?(env)
35
+ end
36
+
37
+ def call(env)
34
38
  # check if browser wants to reauthenticate
35
- if @authenticated_as && http_authorization
39
+ if @authenticated_as && http_authorization(env)
36
40
  @authenticated_as = nil
37
41
  end
42
+
38
43
  # require authentication
39
44
  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
45
+ @connection.ntlm_start
46
+ @authentication_stage ||= 1
47
+ result = process(env)
48
+ return result unless @authenticated_as
49
+ @connection.ntlm_stop
46
50
  end
47
51
 
48
- @request.env[REMOTE_USER] = @authenticated_as
49
- @can_persist = @post_ntlm_can_persist
50
- return super
52
+ # pass thru
53
+ env[REMOTE_USER] = @authenticated_as
54
+ @app.call(env)
51
55
  end
52
56
 
53
- def http_authorization
54
- auth = @request.env[HTTP_AUTHORIZATION]
57
+ # Returns stripped HTTP-Authorization header, nil if none or empty
58
+ def http_authorization(env)
59
+ auth = env[HTTP_AUTHORIZATION]
55
60
  if auth
56
61
  auth = auth.strip
57
62
  auth = nil if auth.empty?
@@ -59,14 +64,23 @@ END
59
64
  auth
60
65
  end
61
66
 
62
- def ntlm_acquire(package = 'NTLM')
63
- ntlm_cleanup
67
+ # Returns token type and value from HTTP-Authorization header
68
+ def token(env)
69
+ auth = http_authorization(env)
70
+ return [nil, nil] unless auth && auth.match(/\A(#{NTLM_ALLOWED_PACKAGE}) (.*)\Z/)
71
+ [$1, Base64.decode64($2.strip)]
72
+ end
73
+
74
+ # Acquires new OS credentials handle
75
+ def acquire(package = 'NTLM')
76
+ cleanup
64
77
  @ntlm = Win32::SSPI::NegotiateServer.new(package)
65
78
  @ntlm.acquire_credentials_handle
66
79
  @ntlm
67
80
  end
68
81
 
69
- def ntlm_cleanup
82
+ # Frees credentials handle, if acquired
83
+ def cleanup
70
84
  if @ntlm
71
85
  @ntlm.cleanup rescue nil
72
86
  @ntlm = nil
@@ -74,55 +88,77 @@ END
74
88
  nil
75
89
  end
76
90
 
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
91
+ # Processes current authentication stage
92
+ # Returns rack response if authentication is incomplete
93
+ # Sets @authenticated_as to username if authentication successful
94
+ def process(env)
84
95
  case @authentication_stage
85
96
  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?
97
+ package, t1 = token(env)
98
+ return request_auth(NTLM_REQUEST_PACKAGE, false) if t1.nil?
99
+ return request_auth unless request.persistent?
89
100
  begin
90
- ntlm_acquire(package)
101
+ acquire(package)
91
102
  t2 = @ntlm.accept_security_context(t1)
92
103
  rescue
93
- return ntlm_request_auth
104
+ return request_auth
94
105
  end
95
- ntlm_request_auth("#{package} #{t2}", false, 2)
106
+ request_auth("#{package} #{t2}", false, 2)
96
107
  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?
108
+ package, t3 = token(env)
109
+ return request_auth(NTLM_REQUEST_PACKAGE, false) if t3.nil?
110
+ return request_auth unless package == @ntlm.package
111
+ return request_auth unless request.persistent?
101
112
  begin
102
113
  t2 = @ntlm.accept_security_context(t3)
103
114
  @authenticated_as = @ntlm.get_username_from_context
104
- @authentication_stage = 1 # in case IE8 wants to reauthenticate
115
+ @authentication_stage = nil # in case IE wants to reauthenticate
105
116
  rescue
106
- return ntlm_request_auth
117
+ return request_auth
107
118
  end
108
- return ntlm_request_auth unless @authenticated_as
109
- ntlm_cleanup
119
+ return request_auth unless @authenticated_as
120
+ cleanup
110
121
  else
111
122
  raise "Invalid value for @authentication_stage=#{@authentication_stage} detected"
112
123
  end
113
- rescue Exception
114
- handle_error
115
- terminate_request
116
- nil
117
124
  end
118
125
 
119
- def ntlm_request_auth(auth = nil, finished = true, next_stage = 1)
126
+ # Returns response with authentication request to the client
127
+ def request_auth(auth = nil, finished = true, next_stage = 1)
120
128
  @authentication_stage = next_stage
121
- @can_persist = !finished
129
+ @connection.can_persist! unless finished
122
130
  head = {}
123
131
  head[WWW_AUTHENTICATE] = auth if auth
124
132
  head[CONTENT_TYPE] = CONTENT_TYPE_AUTH
125
- return [401, head, [AUTHORIZATION_MESSAGE]]
133
+ [401, head, [AUTHORIZATION_MESSAGE]]
134
+ end
135
+ end
136
+
137
+ class NTLMConnection < Connection
138
+ def app=(app)
139
+ super NTLMWrapper.new(app, self)
140
+ end
141
+
142
+ def unbind
143
+ @app.cleanup if @app && @app.respond_to?(:cleanup)
144
+ ensure
145
+ super
146
+ end
147
+
148
+ # Saves original can_persist? value (NTLM will force persistence)
149
+ def ntlm_start
150
+ unless @ntlm_in_progress
151
+ @ntlm_saved_can_persist = @can_persist
152
+ @ntlm_in_progress = true
153
+ end
154
+ end
155
+
156
+ # Restores previous can_persist? value
157
+ def ntlm_stop
158
+ if @ntlm_in_progress
159
+ @can_persist = @ntlm_saved_can_persist
160
+ @ntlm_in_progress = false
161
+ end
126
162
  end
127
163
  end
128
164
  end
@@ -0,0 +1,48 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{thin-auth-ntlm}
8
+ s.version = "0.0.3"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alexey Borzenkov"]
12
+ s.date = %q{2009-08-12}
13
+ s.email = %q{snaury@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE.txt",
16
+ "README.txt"
17
+ ]
18
+ s.files = [
19
+ "LICENSE.txt",
20
+ "README.txt",
21
+ "Rakefile",
22
+ "VERSION.yml",
23
+ "lib/thin-auth-ntlm.rb",
24
+ "lib/thin/ntlm/backends/tcp_server.rb",
25
+ "lib/thin/ntlm/connection.rb",
26
+ "thin-auth-ntlm.gemspec"
27
+ ]
28
+ s.rdoc_options = ["--charset=UTF-8"]
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = %q{1.3.4}
31
+ s.summary = %q{Allows you to force NTLM authentication on Thin TCP servers.}
32
+
33
+ if s.respond_to? :specification_version then
34
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
35
+ s.specification_version = 3
36
+
37
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
38
+ s.add_runtime_dependency(%q<thin>, [">= 1.0.0"])
39
+ s.add_runtime_dependency(%q<rubysspi-server>, [">= 0.0.1"])
40
+ else
41
+ s.add_dependency(%q<thin>, [">= 1.0.0"])
42
+ s.add_dependency(%q<rubysspi-server>, [">= 0.0.1"])
43
+ end
44
+ else
45
+ s.add_dependency(%q<thin>, [">= 1.0.0"])
46
+ s.add_dependency(%q<rubysspi-server>, [">= 0.0.1"])
47
+ end
48
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snaury-thin-auth-ntlm
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
  - Alexey Borzenkov
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-18 00:00:00 -07:00
12
+ date: 2009-08-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -45,11 +45,14 @@ files:
45
45
  - LICENSE.txt
46
46
  - README.txt
47
47
  - Rakefile
48
+ - VERSION.yml
48
49
  - lib/thin-auth-ntlm.rb
49
50
  - lib/thin/ntlm/backends/tcp_server.rb
50
51
  - lib/thin/ntlm/connection.rb
51
- has_rdoc: true
52
+ - thin-auth-ntlm.gemspec
53
+ has_rdoc: false
52
54
  homepage:
55
+ licenses:
53
56
  post_install_message:
54
57
  rdoc_options:
55
58
  - --charset=UTF-8
@@ -70,9 +73,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
73
  requirements: []
71
74
 
72
75
  rubyforge_project:
73
- rubygems_version: 1.2.0
76
+ rubygems_version: 1.3.5
74
77
  signing_key:
75
- specification_version: 2
78
+ specification_version: 3
76
79
  summary: Allows you to force NTLM authentication on Thin TCP servers.
77
80
  test_files: []
78
81