ga_verify 0.0.1

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.
@@ -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
@@ -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,10 @@
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 'ga-verify_types'
8
+
9
+ module GAVerify
10
+ end
@@ -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
@@ -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
@@ -0,0 +1,11 @@
1
+ namespace rb GAVerify
2
+ enum Result {
3
+ SUCCESS = 0,
4
+ BAD_TOKEN = 1,
5
+ BAD_USER = 2,
6
+ NO_GOOGLE_AUTH = 3
7
+ }
8
+
9
+ service Verifier {
10
+ Result check_user(1:string name, 2:i32 token);
11
+ }
@@ -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,11 @@
1
+ module GAVerify
2
+ module Paths
3
+ def self.default_socket
4
+ '/var/run/ga_verifyd.sock'
5
+ end
6
+
7
+ def self.config_path user
8
+ "/home/#{user}/.google_authenticator"
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,9 @@
1
+ module GAVerify
2
+ THRIFT_PATH=File.expand_path(File.join(File.dirname(__FILE__), '/../../gen-rb'))
3
+ end
4
+
5
+ $LOAD_PATH.push(GAVerify::THRIFT_PATH)
6
+ require 'verifier'
7
+ require 'ga-verify_constants'
8
+ require 'ga-verify_types'
9
+ $LOAD_PATH.pop
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
+