ga_verify 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ga-verify +33 -0
- data/bin/ga-verifyd +24 -0
- data/gen-rb/ga-verify_constants.rb +10 -0
- data/gen-rb/ga-verify_types.rb +18 -0
- data/gen-rb/verifier.rb +85 -0
- data/if/ga-verify.thrift +11 -0
- data/lib/ga_verify.rb +1 -0
- data/lib/ga_verify/client.rb +21 -0
- data/lib/ga_verify/handler.rb +48 -0
- data/lib/ga_verify/paths.rb +11 -0
- data/lib/ga_verify/server.rb +19 -0
- data/lib/ga_verify/thrift.rb +9 -0
- metadata +88 -0
data/bin/ga-verify
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
_SELF=File.readlink(__FILE__) rescue __FILE__
|
3
|
+
_ROOT=File.expand_path(File.dirname(_SELF) + '/../lib')
|
4
|
+
$LOAD_PATH.push _ROOT
|
5
|
+
|
6
|
+
require 'ga_verify/paths'
|
7
|
+
options = {
|
8
|
+
:socket => GAVerify::Paths.default_socket,
|
9
|
+
}
|
10
|
+
|
11
|
+
require 'optparse'
|
12
|
+
|
13
|
+
optparse = OptionParser.new do |opts|
|
14
|
+
opts.banner += " USER TOKEN"
|
15
|
+
opts.on(
|
16
|
+
'-s', '--socket PATH',
|
17
|
+
"Default: #{options[:socket]}"
|
18
|
+
) do |path|
|
19
|
+
options[:socket] = path
|
20
|
+
end
|
21
|
+
end
|
22
|
+
optparse.parse!
|
23
|
+
|
24
|
+
if ARGV.size != 2
|
25
|
+
STDERR.write optparse.help
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
user, token = ARGV[0], ARGV[1].to_i
|
29
|
+
|
30
|
+
require 'ga_verify/client'
|
31
|
+
result = GAVerify::Client.new(options).check_user(user, token)
|
32
|
+
puts GAVerify::Result::VALUE_MAP[result]
|
33
|
+
exit result
|
data/bin/ga-verifyd
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
_SELF=File.readlink(__FILE__) rescue __FILE__
|
3
|
+
_ROOT=File.expand_path(File.dirname(_SELF) + '/../lib')
|
4
|
+
$LOAD_PATH.push _ROOT
|
5
|
+
|
6
|
+
require 'ga_verify/paths'
|
7
|
+
options = {
|
8
|
+
:socket => GAVerify::Paths.default_socket,
|
9
|
+
}
|
10
|
+
|
11
|
+
require 'optparse'
|
12
|
+
|
13
|
+
optparse = OptionParser.new do |opts|
|
14
|
+
opts.on(
|
15
|
+
'-s', '--socket PATH',
|
16
|
+
"Default: #{options[:socket]}"
|
17
|
+
) do |path|
|
18
|
+
options[:socket] = path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
optparse.parse!
|
22
|
+
|
23
|
+
require 'ga_verify/server'
|
24
|
+
GAVerify::Server.new(options[:socket]).serve!
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
|
8
|
+
module GAVerify
|
9
|
+
module Result
|
10
|
+
SUCCESS = 0
|
11
|
+
BAD_TOKEN = 1
|
12
|
+
BAD_USER = 2
|
13
|
+
NO_GOOGLE_AUTH = 3
|
14
|
+
VALUE_MAP = {0 => "SUCCESS", 1 => "BAD_TOKEN", 2 => "BAD_USER", 3 => "NO_GOOGLE_AUTH"}
|
15
|
+
VALID_VALUES = Set.new([SUCCESS, BAD_TOKEN, BAD_USER, NO_GOOGLE_AUTH]).freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/gen-rb/verifier.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# Autogenerated by Thrift
|
3
|
+
#
|
4
|
+
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'thrift'
|
8
|
+
require 'ga-verify_types'
|
9
|
+
|
10
|
+
module GAVerify
|
11
|
+
module Verifier
|
12
|
+
class Client
|
13
|
+
include ::Thrift::Client
|
14
|
+
|
15
|
+
def check_user(name, token)
|
16
|
+
send_check_user(name, token)
|
17
|
+
return recv_check_user()
|
18
|
+
end
|
19
|
+
|
20
|
+
def send_check_user(name, token)
|
21
|
+
send_message('check_user', Check_user_args, :name => name, :token => token)
|
22
|
+
end
|
23
|
+
|
24
|
+
def recv_check_user()
|
25
|
+
result = receive_message(Check_user_result)
|
26
|
+
return result.success unless result.success.nil?
|
27
|
+
raise ::Thrift::ApplicationException.new(::Thrift::ApplicationException::MISSING_RESULT, 'check_user failed: unknown result')
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class Processor
|
33
|
+
include ::Thrift::Processor
|
34
|
+
|
35
|
+
def process_check_user(seqid, iprot, oprot)
|
36
|
+
args = read_args(iprot, Check_user_args)
|
37
|
+
result = Check_user_result.new()
|
38
|
+
result.success = @handler.check_user(args.name, args.token)
|
39
|
+
write_result(result, oprot, 'check_user', seqid)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# HELPER FUNCTIONS AND STRUCTURES
|
45
|
+
|
46
|
+
class Check_user_args
|
47
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
48
|
+
NAME = 1
|
49
|
+
TOKEN = 2
|
50
|
+
|
51
|
+
FIELDS = {
|
52
|
+
NAME => {:type => ::Thrift::Types::STRING, :name => 'name'},
|
53
|
+
TOKEN => {:type => ::Thrift::Types::I32, :name => 'token'}
|
54
|
+
}
|
55
|
+
|
56
|
+
def struct_fields; FIELDS; end
|
57
|
+
|
58
|
+
def validate
|
59
|
+
end
|
60
|
+
|
61
|
+
::Thrift::Struct.generate_accessors self
|
62
|
+
end
|
63
|
+
|
64
|
+
class Check_user_result
|
65
|
+
include ::Thrift::Struct, ::Thrift::Struct_Union
|
66
|
+
SUCCESS = 0
|
67
|
+
|
68
|
+
FIELDS = {
|
69
|
+
SUCCESS => {:type => ::Thrift::Types::I32, :name => 'success', :enum_class => GAVerify::Result}
|
70
|
+
}
|
71
|
+
|
72
|
+
def struct_fields; FIELDS; end
|
73
|
+
|
74
|
+
def validate
|
75
|
+
unless @success.nil? || GAVerify::Result::VALID_VALUES.include?(@success)
|
76
|
+
raise ::Thrift::ProtocolException.new(::Thrift::ProtocolException::UNKNOWN, 'Invalid value of field success!')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
::Thrift::Struct.generate_accessors self
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/if/ga-verify.thrift
ADDED
data/lib/ga_verify.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'ga_verify/client'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'ga_verify/thrift'
|
2
|
+
require 'ga_verify/paths'
|
3
|
+
|
4
|
+
require 'thrift'
|
5
|
+
|
6
|
+
module GAVerify
|
7
|
+
class Client
|
8
|
+
def initialize options={}
|
9
|
+
options[:socket] ||= GAVerify::Paths.default_socket
|
10
|
+
socket = Thrift::UNIXSocket.new(options[:socket])
|
11
|
+
transport = Thrift::FramedTransport.new(socket)
|
12
|
+
protocol = Thrift::BinaryProtocol.new(transport)
|
13
|
+
@client = GAVerify::Verifier::Client.new(protocol)
|
14
|
+
transport.open
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing *args
|
18
|
+
@client.send *args
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ga_verify/thrift'
|
2
|
+
require 'ga_verify/paths'
|
3
|
+
|
4
|
+
require 'rotp'
|
5
|
+
|
6
|
+
module GAVerify
|
7
|
+
class Handler
|
8
|
+
def initialize
|
9
|
+
@last_seen = Hash.new(0)
|
10
|
+
@used_tokens = Hash.new{Hash.new(0)}
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_user user, token
|
14
|
+
unless user =~ /^[a-z]+$/
|
15
|
+
return GAVerify::Result::BAD_USER
|
16
|
+
end
|
17
|
+
unless File.exists? "/home/#{user}"
|
18
|
+
return GAVerify::Result::BAD_USER
|
19
|
+
end
|
20
|
+
path = GAVerify::Paths.config_path(user)
|
21
|
+
unless File.exists? path
|
22
|
+
return GAVerify::Result::NO_GOOGLE_AUTH
|
23
|
+
end
|
24
|
+
now = Time.now.to_i
|
25
|
+
# Max one login every 15s
|
26
|
+
if @last_seen[user] >= now - 15
|
27
|
+
return GAVerify::Result::BAD_TOKEN
|
28
|
+
end
|
29
|
+
@last_seen[user] = now
|
30
|
+
|
31
|
+
secret = File.open(path, 'r').first.strip
|
32
|
+
totp = ROTP::TOTP.new(secret)
|
33
|
+
|
34
|
+
# Allow +- 1 token
|
35
|
+
times = [now - 30, now, now + 30]
|
36
|
+
if times.any?{|time| totp.verify(token, time)}
|
37
|
+
# disallow token re-use within 10 minutes
|
38
|
+
if @used_tokens[user][token] < now - 600
|
39
|
+
@used_tokens[user][token] = now
|
40
|
+
# Cleanup
|
41
|
+
@used_tokens[user].reject!{|k,v| used_tokens[user][token] < now - 600}
|
42
|
+
return GAVerify::Result::SUCCESS
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return GAVerify::Result::BAD_TOKEN
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ga_verify/handler'
|
2
|
+
|
3
|
+
require 'thrift'
|
4
|
+
|
5
|
+
module GAVerify
|
6
|
+
class Server < GAVerify::Handler
|
7
|
+
def initialize socket_path
|
8
|
+
handler = GAVerify::Handler.new
|
9
|
+
processor = GAVerify::Verifier::Processor.new handler
|
10
|
+
transport = Thrift::FramedTransportFactory.new
|
11
|
+
socket = Thrift::UNIXServerSocket.new(socket_path)
|
12
|
+
@server = Thrift::NonblockingServer.new processor, socket, transport
|
13
|
+
end
|
14
|
+
|
15
|
+
def serve!
|
16
|
+
@server.serve
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ga_verify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Fred Emmott
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-08-01 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rotp
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.0
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: thrift
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.6.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
description: Provides a unix socket for validating tokens
|
38
|
+
email:
|
39
|
+
- mail@fredemmott.co.uk
|
40
|
+
executables:
|
41
|
+
- ga-verify
|
42
|
+
- ga-verifyd
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
files:
|
48
|
+
- bin/ga-verifyd
|
49
|
+
- bin/ga-verify
|
50
|
+
- lib/ga_verify.rb
|
51
|
+
- lib/ga_verify/paths.rb
|
52
|
+
- lib/ga_verify/thrift.rb
|
53
|
+
- lib/ga_verify/client.rb
|
54
|
+
- lib/ga_verify/handler.rb
|
55
|
+
- lib/ga_verify/server.rb
|
56
|
+
- gen-rb/verifier.rb
|
57
|
+
- gen-rb/ga-verify_constants.rb
|
58
|
+
- gen-rb/ga-verify_types.rb
|
59
|
+
- if/ga-verify.thrift
|
60
|
+
homepage: https://github.com/fredemmott/ga-verify
|
61
|
+
licenses: []
|
62
|
+
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.7.2
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: Thrift client and server for validating google authenticator tokens
|
87
|
+
test_files: []
|
88
|
+
|