sq_auth 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/.gitignore +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/Rakefile +7 -0
  5. data/examples/client.rb +23 -0
  6. data/examples/server.rb +37 -0
  7. data/lib/sq_auth/sq_auth_access.rb +103 -0
  8. data/lib/sq_auth/sq_auth_client.rb +72 -0
  9. data/lib/sq_auth/sq_auth_helpers/sq_auth_helpers_dsl.rb +61 -0
  10. data/lib/sq_auth/sq_auth_helpers/sq_auth_helpers_rails.rb +39 -0
  11. data/lib/sq_auth/sq_auth_helpers/sq_auth_helpers_sinatra.rb +25 -0
  12. data/lib/sq_auth/sq_auth_integration/sq_auth_action_controller.rb +16 -0
  13. data/lib/sq_auth/sq_auth_integration/sq_auth_integration.rb +23 -0
  14. data/lib/sq_auth/sq_auth_integration/sq_auth_rack.rb +89 -0
  15. data/lib/sq_auth/sq_auth_integration/sq_auth_rack_protection.rb +28 -0
  16. data/lib/sq_auth/sq_auth_integration/sq_auth_sinatra.rb +36 -0
  17. data/lib/sq_auth/sq_auth_request.rb +88 -0
  18. data/lib/sq_auth/sq_auth_server_interface/basic_server.rb +40 -0
  19. data/lib/sq_auth/sq_auth_sessions.rb +16 -0
  20. data/lib/sq_auth/sq_auth_user/basic_user.rb +10 -0
  21. data/lib/sq_auth/sq_auth_user/rack_user.rb +11 -0
  22. data/lib/sq_auth/sq_auth_utils.rb +12 -0
  23. data/lib/sq_auth/version.rb +3 -0
  24. data/lib/sq_auth.rb +68 -0
  25. data/spec/lib/sq_auth/sq_auth_client_spec.rb +30 -0
  26. data/spec/lib/sq_auth/sq_auth_request_spec.rb +40 -0
  27. data/spec/lib/sq_auth/sq_auth_server_interface/basic_server_spec.rb +24 -0
  28. data/spec/lib/sq_auth/sq_auth_sessions_spec.rb +3 -0
  29. data/spec/lib/sq_auth/sq_auth_user/basic_user_spec.rb +5 -0
  30. data/spec/lib/sq_auth_spec.rb +5 -0
  31. data/spec/spec_helper.rb +1 -0
  32. data/sq_auth.gemspec +24 -0
  33. metadata +125 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.*.sw*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sq_auth.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1,23 @@
1
+ require 'sinatra'
2
+ require 'sq_auth'
3
+
4
+ enable :sessions
5
+ set :port, 7842
6
+
7
+ SqAuth.connect(host: "localhost", port: 3000) do |d|
8
+ d.project_name = "Project"
9
+ end
10
+
11
+ get ["admin"], "/something" do
12
+ <<-EOF
13
+ Logined to something with params #{params}
14
+ <br>
15
+ #{SqAuth.with_sq_auth("admin::super", "Project"){"You can't see it"}}
16
+ <br>
17
+ #{access_for("admin"){"You can see it"}}
18
+ EOF
19
+ end
20
+
21
+ get "/abc" do
22
+ params.to_s
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'sinatra'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'uri'
5
+ set :port, 7843
6
+
7
+ get "/health" do
8
+ "OK"
9
+ end
10
+
11
+ post "/check_role" do
12
+ unless params[:role][/admin/]
13
+ {:role_exist => true}.to_json
14
+ else
15
+ {:role_exist => false}.to_json
16
+ end
17
+ end
18
+
19
+ get "/login" do
20
+ uri = URI::parse(params[:callback])
21
+ new_uri = URI::HTTP.build(host: uri.host, port: uri.port, path: "/save_session")
22
+
23
+ <<-EOF
24
+ <body>
25
+ <a href='#{params[:callback]}'>Back</a>
26
+ <form action="#{new_uri}" method="post">
27
+ <input type="text" name="sqauthsession" value="mydata" />
28
+ <input style="display:none" type="text" name="callback" value="#{params[:callback]}" />
29
+ <input type="submit" />
30
+ </form>
31
+ </body>
32
+ EOF
33
+ end
34
+
35
+ get "/push_session" do
36
+ push_session_to_client params[:client]
37
+ end
@@ -0,0 +1,103 @@
1
+ module SqAuth
2
+ class SqAuthAccess
3
+ DEFAULT_ACCESS_PATH = "/access_partial"
4
+ DEFAULT_DRAW_PROC = Proc.new {|uri, callback, role, project, session| SqAuthUtils::default_draw_template(uri, callback, role, project, session)}
5
+ DEFAULT_DATA_PROC = Proc.new { "Forbidden" }
6
+ DEFAULT_OPTIONS = {project: "Project", https: true}
7
+ attr_accessor :login_path, :callback, :project_name, :gateway_ip
8
+ def initialize options={}
9
+ @options = options
10
+ @data_proc = DEFAULT_DATA_PROC
11
+ @draw_proc = DEFAULT_DRAW_PROC
12
+ @login_path = DEFAULT_ACCESS_PATH
13
+ @gateway_ip = nil
14
+ end
15
+
16
+ def connect options = {}
17
+ options = DEFAULT_OPTIONS.merge(options)
18
+ @project_name = options[:project]
19
+ @gateway_ip = options[:gateway_ip]
20
+ yield self if block_given?
21
+ SqAuthIntegration.alter_environment options
22
+ @session_provider = SqAuthClient.new options
23
+ end
24
+
25
+ def draw_when_not_logged_in &block
26
+ @draw_proc = block
27
+ end
28
+
29
+ def data_when_not_logged_in &block
30
+ @data_proc = Proc.new {|*args| block.call(*args)}
31
+ end
32
+
33
+ def get_not_logged_in_proc type = nil
34
+ if type == true || type.nil?
35
+ @draw_proc
36
+ else
37
+ @data_proc
38
+ end
39
+ end
40
+
41
+ def check_session_provider
42
+ raise "Authentication service not specified" unless @session_provider
43
+ # raise "Authentication service unavailable" unless @session_provider.available?
44
+ end
45
+
46
+ def api_filter(roles, project = @project_name, when_ok, when_no_role, options)
47
+ check_session_provider
48
+ not_logged_in_proc = get_not_logged_in_proc(options[:draw])
49
+ if sq_auth_filter(roles, project, options)
50
+ when_ok.call
51
+ else
52
+ when_no_role.(not_logged_in_proc.(login_to, callback, roles, project, @session_provider.session_for_current_user))
53
+ end
54
+ end
55
+
56
+ def sq_auth_filter(roles, project = @project_name, options = {})
57
+ @session_provider.session_for_current_user && @session_provider.role_exist_for_current_user?(roles, project)
58
+ end
59
+
60
+
61
+ def when_not_authenticated(roles, project, options = {})
62
+ not_logged_in_proc = get_not_logged_in_proc(options[:draw])
63
+ not_logged_in_proc.call(login_to, callback, roles, project, @session_provider.session_for_current_user)
64
+ end
65
+
66
+ def draw_when_not_authenticated(roles, project = @project_name)
67
+ when_not_authenticated(roles, project, {:draw => true})
68
+ end
69
+
70
+ def message_when_not_authenticated(roles = [], project = @project_name)
71
+ when_not_authenticated(roles, project, {:draw => false})
72
+ end
73
+
74
+ def with_sq_auth(roles, project = @project_name, options = {}, &block)
75
+ check_session_provider
76
+ binded_self = options[:binding].is_a?(Binding) ? eval("self", options[:binding]) : self
77
+ if sq_auth_filter(roles, project, options)
78
+ binded_self.instance_eval(&block) if block_given?
79
+ else
80
+ when_not_authenticated(roles, project, options)
81
+ end
82
+ end
83
+
84
+ def save_session_for_current_user sqauthsession
85
+ @session_provider.create_session_for_current_user sqauthsession
86
+ end
87
+
88
+ def current_user_ip= ip
89
+ if @gateway_ip
90
+ @session_provider.user.user_ip = @gateway_ip
91
+ else
92
+ @session_provider.user.user_ip = ip
93
+ end
94
+ p @session_provider.user.user_ip
95
+ end
96
+
97
+ def login_to
98
+ uri = @session_provider.auth_server_uri
99
+ uri.path = "#@login_path"
100
+ uri.to_s
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,72 @@
1
+ module SqAuth
2
+ class SqAuthClient
3
+
4
+ def initialize options = {}
5
+ @https = !!options[:https]
6
+ @host = options[:host] || "localhost"
7
+ @port = (options[:port] || (@https ? 443 : 80)).to_i
8
+ @username = options[:username]
9
+ @password = options[:password]
10
+ @server = options[:server_type] || SqAuth::SqAuthServer::BasicServer
11
+ @user = options[:user_type] || SqAuth::SqAuthUser::BasicUser.new
12
+ @sessions = SqAuth::SqAuthSessions.new
13
+ end
14
+
15
+ def create_session_for_current_user session
16
+ create_session current_user, session
17
+ end
18
+
19
+ def session_for_current_user
20
+ session_for current_user
21
+ end
22
+
23
+ def check_connection
24
+ send_request :check_connection
25
+ end
26
+
27
+ def available?
28
+ response = check_connection
29
+ response.is_a?(Hash) && response[:status] == "200"
30
+ end
31
+
32
+ def role_exist_for_current_user? role, project
33
+ role_exist? current_user, role, project
34
+ end
35
+
36
+ def user
37
+ @user
38
+ end
39
+
40
+ def current_user
41
+ @user.current_user
42
+ end
43
+
44
+ def create_session user, session
45
+ @sessions[user] = session
46
+ end
47
+
48
+ def session_for user
49
+ p @sessions
50
+ @sessions[user]
51
+ end
52
+
53
+ def role_exist? user, roles, project
54
+ request_hash = {sqauthsession: session_for(user), roles: [*roles], auth_name: project, ip: user[:ip]}
55
+ response = send_request :check_role, request_hash
56
+ response.is_a?(Hash) && response[:data].is_a?(Hash) && (response[:data]["role_exist"] == true)
57
+ end
58
+
59
+ def send_request request_name, params = nil
60
+ @server.send(request_name, params, host_options)
61
+ end
62
+
63
+ def host_options
64
+ {host: @host, port: @port, username: @username, password: @password, https: @https}
65
+ end
66
+
67
+ def auth_server_uri
68
+ uri_builder = (@https ? URI::HTTPS : URI::HTTP)
69
+ uri_builder.build(host: @host, port: @port)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,61 @@
1
+ module SqAuth
2
+ module SqAuthHelpers
3
+ module DSL
4
+ def sq_auth_access &block
5
+ self.instance_eval &block
6
+ end
7
+
8
+ def access_actions *actions, &block
9
+ @sq_auth_actions_only = *actions
10
+ yield block if block_given?
11
+ @sq_auth_actions_only = nil
12
+ end
13
+
14
+ def access_action *action, &block
15
+ access_actions [*action], &block
16
+ end
17
+
18
+
19
+
20
+ def draw_for *roles, &block
21
+ access_for([*roles], &block)
22
+ end
23
+
24
+ end
25
+
26
+ module SinatraDSL
27
+ def show_to *roles
28
+ create_filter [*roles]
29
+ end
30
+ def execute_for *roles
31
+ create_filter [*roles], {draw: false}
32
+ end
33
+ end
34
+
35
+ module RailsDSL
36
+ def access_actions_except *actions, &block
37
+ @sq_auth_actions_except = *actions
38
+ yield block if block_given?
39
+ @sq_auth_actions_except = nil
40
+ end
41
+
42
+ def access_action_except *action, &block
43
+ access_actions_except [*action], &block
44
+ end
45
+
46
+ def method_missing m, *args, &block
47
+ begin
48
+ super
49
+ rescue NoMethodError
50
+ if m[/^show_.+_to$/]
51
+ format = m.to_s.scan(/^show_(.+)_to$/).flatten.first
52
+ create_filter args, {:format_type => format}
53
+ else
54
+ raise NoMethodError
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,39 @@
1
+ module SqAuth
2
+ module SqAuthHelpers
3
+ module ActionController
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ include SqAuth::SqAuthHelpers::DSL
10
+ include SqAuth::SqAuthHelpers::RailsDSL
11
+ def create_filter roles, options = {}
12
+ filter_options = {}
13
+ filter_options[:only] = @sq_auth_actions_only
14
+ filter_options[:except] = @sq_auth_actions_except
15
+ before_filter(filter_options) do |controller|
16
+ format_type = options[:format_type]
17
+ format_condition = (format_type == "all") || (format_type.nil?) || (controller.request.format.send("#{format_type}?".to_sym))
18
+ if format_condition
19
+ error_proc = nil
20
+ api_options = {}
21
+ if format_type == "json"
22
+ error_proc = Proc.new do |message|
23
+ render json: message
24
+ end
25
+ api_options[:draw] = false
26
+ else
27
+ error_proc = Proc.new do |message|
28
+ render text: message
29
+ end
30
+ api_options[:draw] = true
31
+ end
32
+ SqAuth.api_filter(roles, Proc.new {}, error_proc, api_options)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ module SqAuth
2
+ module SqAuthHelpers
3
+ module Sinatra
4
+ include SqAuth::SqAuthHelpers::SinatraDSL
5
+ include SqAuth::SqAuthHelpers::DSL
6
+
7
+ def create_filter roles, options = {}
8
+ action = nil
9
+ action = [*@sq_auth_actions_only].flatten.first if @sq_auth_actions_only
10
+
11
+ if !roles.empty?
12
+ ok_proc = Proc.new {}
13
+ error_proc = Proc.new do |message|
14
+ throw(:halt, [401, message])
15
+ end
16
+ before(action) do
17
+ SqAuth.api_filter(roles, ok_proc, error_proc, options)
18
+ end
19
+ end
20
+ end
21
+
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ module SqAuth
2
+ module SqAuthIntegration
3
+ module SqAuthActionController
4
+ def self.check_environment
5
+ defined?(ActionController::Base)
6
+ end
7
+
8
+ def self.alter_environment options={}
9
+ ActionController::Base.instance_eval do
10
+ include SqAuth::SqAuthHelpers::ActionController
11
+ end
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module SqAuth
2
+ module SqAuthIntegration
3
+ def self.alter_environment options = {}
4
+ @already_altered ||= []
5
+ alter_modules = SqAuth::SqAuthIntegration.constants.map do |const|
6
+ alter_module = nil
7
+ check_module = SqAuth::SqAuthIntegration.const_get(const)
8
+ if check_module.kind_of?(Module) && check_module.respond_to?(:alter_environment) && check_module.respond_to?(:check_environment)
9
+ alter_module = check_module
10
+ end
11
+ alter_module
12
+ end.compact
13
+ alter_modules.each do |m|
14
+ unless @already_altered.include? m
15
+ if m.check_environment
16
+ @already_altered << m
17
+ m.alter_environment options
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,89 @@
1
+ module SqAuth
2
+ module SqAuthIntegration
3
+ module SqAuthRack
4
+ def self.check_environment
5
+ defined?(Rack)
6
+ end
7
+ def self.alter_environment options={}
8
+ if defined?(Rails)
9
+ Rails.application.class.instance_eval do
10
+ config.middleware.use Rack::Session::Cookie, :expire_after => 2592000
11
+ config.middleware.use SqAuth::SqAuthIntegration::SqAuthRack::Middleware
12
+ end
13
+ else
14
+ use Rack::Session::Cookie, :expire_after => 2592000
15
+ use SqAuth::SqAuthIntegration::SqAuthRack::Middleware
16
+ end
17
+ end
18
+
19
+ class Middleware
20
+ attr_accessor :app, :env
21
+ def call(env)
22
+ req = Rack::Request.new(env)
23
+ SqAuth.access.callback = callback_uri(env)
24
+ SqAuth.access.current_user_ip = env["HTTP_X_FORWARDED_FOR"] || env["REMOTE_ADDR"]
25
+ SqAuth.access.save_session_for_current_user (env["rack.session"]||{})[:sqauthsession]
26
+ form_hash = req.params||{}
27
+ if auth_request?(env, form_hash)
28
+ redirect_to_callback(env, form_hash)
29
+ else
30
+ pass_through env
31
+ end
32
+ end
33
+
34
+ def auth_request? env, form_hash
35
+ env["REQUEST_METHOD"] == "POST" && form_hash.keys.include?("sqauthsession") && form_hash.keys.include?("callback")
36
+ end
37
+
38
+ def redirect_to_callback env, form_hash
39
+ env["rack.session"][:sqauthsession] = form_hash["sqauthsession"] if env["rack.session"]
40
+ SqAuth.access.save_session_for_current_user form_hash["sqauthsession"]
41
+
42
+ [302, {'Location' => form_hash["callback"]}, ['Authenticated']]
43
+ end
44
+
45
+ def callback_uri env
46
+ if URI.parse(env["REQUEST_URI"]).host
47
+ env["REQUEST_URI"]
48
+ else
49
+ uri_type = URI.const_get(env["HTTP_X_URL_SCHEME"].upcase) rescue nil
50
+ uri_type ||= URI.const_get(env["rack.url_scheme"].upcase) rescue nil
51
+ uri_type ||= URI::HTTP
52
+ if env["HTTP_HOST"].is_a? String
53
+ host, port = env["HTTP_HOST"].split(":")
54
+ end
55
+ host ||= env["SERVER_NAME"]
56
+ port ||= env["SERVER_PORT"]
57
+ path = env["REQUEST_PATH"].to_s
58
+ if path.empty?
59
+ path = URI::parse(env["PATH_INFO"]).path rescue ""
60
+ end
61
+ if path.empty?
62
+ path = URI::parse(env["REQUEST_URI"]).path
63
+ end
64
+ query = env["QUERY_STRING"]
65
+ if port
66
+ uri = uri_type.build(host: host, port: port.to_i, path: path, query: query)
67
+ else
68
+ uri = uri_type.build(host: host, path: path, query: query)
69
+ end
70
+ uri.to_s
71
+ end
72
+ rescue Exception => ex
73
+ p ex.message
74
+ return ""
75
+ end
76
+
77
+ def pass_through env
78
+ status, headers, response = app.call(env)
79
+ [status, headers, response]
80
+ end
81
+
82
+ def initialize(app)
83
+ @app = app
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,28 @@
1
+ module SqAuth
2
+ module SqAuthIntegration
3
+ module SqAuthRackProtection
4
+
5
+ def self.check_environment
6
+ defined?(Rack::Protection::RemoteToken)
7
+ end
8
+
9
+ def self.alter_environment options={}
10
+ # Sorry, Konstantin
11
+ except_host = options[:host]
12
+ Rack::Protection::RemoteToken.class_exec(except_host) do |except|
13
+ const_set("HOST", except)
14
+ alias :old_accepts? :accepts?
15
+ def accepts?(env)
16
+ form_hash = env["rack.request.form_hash"]||{}
17
+ if referrer(env) == HOST && env["REQUEST_METHOD"] == "POST" && form_hash.keys.include?("sqauthsession")
18
+ true
19
+ else
20
+ old_accepts?(env)
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module SqAuth
2
+ module SqAuthIntegration
3
+ module SqAuthSinatra
4
+
5
+ def self.check_environment
6
+ defined?(Sinatra)
7
+ end
8
+
9
+ def self.alter_environment options={}
10
+ Sinatra.register SqAuth::SqAuthHelpers::Sinatra
11
+ Sinatra::Base.instance_eval do
12
+ alias :old_get :get
13
+ def get(*args, &block)
14
+ roles = []
15
+ if args[0].is_a?(Array)
16
+ roles << args[0]
17
+ args.shift
18
+ end
19
+ roles.flatten!
20
+ if !roles.empty?
21
+ ok_proc = Proc.new {}
22
+ error_proc = Proc.new do |message|
23
+ throw(:halt, [401, message])
24
+ end
25
+ before(*args) do
26
+ SqAuth.api_filter(roles, ok_proc, error_proc)
27
+ end
28
+ end
29
+ old_get(*args, &block)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,88 @@
1
+ module SqAuth
2
+ class SqAuthRequest
3
+
4
+ def self.hash_to_query hash
5
+ query = ""
6
+ encode_chars = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
7
+ if hash.is_a? Hash
8
+ query = hash.map do |param_name, param_value|
9
+ if param_value.is_a? Array
10
+ param_value.map do |v|
11
+ "#{param_name}[]=#{URI::encode(v.to_s, encode_chars)}"
12
+ end.join("&")
13
+ else
14
+ "#{param_name}=#{URI::encode(param_value.to_s, encode_chars)}"
15
+ end
16
+ end.join("&")
17
+ end
18
+ query
19
+ end
20
+
21
+ def self.parse_response response = nil
22
+ data = nil
23
+ if response.is_a? Net::HTTPResponse
24
+ data = {}
25
+ data[:status] = response.code
26
+ data[:message] = response.message
27
+ if response.is_a? Net::HTTPOK
28
+ data[:data] = begin
29
+ JSON::load(response.body)
30
+ rescue JSON::ParserError
31
+ response.body
32
+ end
33
+ end
34
+ end
35
+ data
36
+ end
37
+
38
+ def initialize options
39
+ @host = options[:host] || raise("Host not specified")
40
+ @port = options[:port] || 80
41
+ @username = options[:username]
42
+ @password = options[:password]
43
+ path = options[:path]
44
+ absolute_path = "/"
45
+ if path.is_a? Symbol
46
+ absolute_path << path.to_s
47
+ elsif path.is_a? String
48
+ absolute_path << path
49
+ end
50
+ @path = absolute_path
51
+ method = options[:method] || :get
52
+ @https = !!options[:https]
53
+ @method = ::Net::HTTP.const_get(method.to_s.capitalize)
54
+ @uri_builder = @https ? URI::HTTPS : URI::HTTP
55
+ end
56
+
57
+ def setup_query query_hash
58
+ @query = SqAuthRequest.hash_to_query(query_hash)
59
+ @uri = @uri_builder.build(host: @host, port: @port, path: @path, query: (@method == Net::HTTP::Get)? @query: nil)
60
+ @http = Net::HTTP.new(@uri.host, @uri.port)
61
+ @http.use_ssl = @https
62
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @https
63
+
64
+ end
65
+
66
+ def request query = {}
67
+ setup_query(query)
68
+ response = get_response
69
+ SqAuthRequest.parse_response response
70
+ end
71
+
72
+ def get_response
73
+ request = @method.new(@uri.request_uri)
74
+ if @username && @password
75
+ request.basic_auth @username, @password
76
+ end
77
+ send_data(request)
78
+ end
79
+
80
+ def send_data request
81
+ if @method == Net::HTTP::Post
82
+ request.body = @query
83
+ request.content_length = request.body.bytesize
84
+ end
85
+ @http.request(request) rescue nil
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,40 @@
1
+ module SqAuth
2
+ module SqAuthServer
3
+ class BasicServer
4
+ SERVER_INTERFACE = {
5
+ check_connection: {path: "health", method: :get},
6
+ check_role: {path: "check_role", method: :post}
7
+ }
8
+
9
+ def self.init_request specification, host_options = {}
10
+ options = {}
11
+ options[:host] = host_options[:host]
12
+ options[:port] = host_options[:port]
13
+ options[:username] = host_options[:username]
14
+ options[:password] = host_options[:password]
15
+ options[:https] = host_options[:https]
16
+ options[:path] = specification[:path]
17
+ options[:method] = specification[:method]
18
+ SqAuthRequest.new options
19
+ end
20
+
21
+ def self.sq_auth_host host_options
22
+ {host: host_options[:host], port: host_options[:port]}
23
+ end
24
+
25
+ def self.use_interface interface, query, host_options = {}
26
+ interface[:requests] ||= {}
27
+ interface[:requests][sq_auth_host(host_options)] ||= init_request(interface, host_options)
28
+ interface[:requests][sq_auth_host(host_options)].request query
29
+ end
30
+
31
+ def self.method_missing m, *args, &block
32
+ if SERVER_INTERFACE[m]
33
+ use_interface(SERVER_INTERFACE[m], *args)
34
+ else
35
+ super
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ module SqAuth
2
+ class SqAuthSessions
3
+ def initialize
4
+ @sessions = {}
5
+ end
6
+
7
+ def [] key
8
+ @sessions[key]
9
+ end
10
+
11
+ def []= key, value
12
+ @sessions[key] = value
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module SqAuth
2
+ module SqAuthUser
3
+ class BasicUser
4
+ attr_accessor :user_name, :user_ip
5
+ def current_user
6
+ {name: (user_name || "Anonymous"), ip: (user_ip || "127.0.0.1")}
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module SqAuth
2
+ module SqAuthUser
3
+ class RackUser < BasicUser
4
+ attr_accessor :user_ip, :user_name
5
+
6
+ def current_user
7
+ {name: (user_name || "Anonymous"), ip: (user_ip || "127.0.0.1")}
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module SqAuth
2
+ module SqAuthUtils
3
+ def self.default_draw_template uri, callback, role, project, session
4
+ <<-EOF
5
+ <div class="sq_auth_not_logged_in">
6
+ <iframe src='#{uri}?#{SqAuth::SqAuthRequest.hash_to_query({callback: callback, roles: [*role], auth_name: project, sqauthsession: session})}'>
7
+ </iframe>
8
+ </div>
9
+ EOF
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module SqAuth
2
+ VERSION = "0.0.18"
3
+ end
data/lib/sq_auth.rb ADDED
@@ -0,0 +1,68 @@
1
+ # external dependencies
2
+ require 'uri'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'openssl'
6
+ require 'json'
7
+ require 'digest'
8
+
9
+ # internal dependencies
10
+ require "sq_auth/version"
11
+ require "sq_auth/sq_auth_access"
12
+ require "sq_auth/sq_auth_client"
13
+ require "sq_auth/sq_auth_request"
14
+ require "sq_auth/sq_auth_sessions"
15
+ require "sq_auth/sq_auth_utils"
16
+ require "sq_auth/sq_auth_server_interface/basic_server"
17
+ require "sq_auth/sq_auth_user/basic_user"
18
+ require "sq_auth/sq_auth_user/rack_user"
19
+ require "sq_auth/sq_auth_integration/sq_auth_integration"
20
+ require "sq_auth/sq_auth_integration/sq_auth_rack"
21
+ require "sq_auth/sq_auth_integration/sq_auth_rack_protection"
22
+ require "sq_auth/sq_auth_integration/sq_auth_sinatra"
23
+ require "sq_auth/sq_auth_integration/sq_auth_action_controller"
24
+ require "sq_auth/sq_auth_helpers/sq_auth_helpers_dsl"
25
+ require "sq_auth/sq_auth_helpers/sq_auth_helpers_rails"
26
+ require "sq_auth/sq_auth_helpers/sq_auth_helpers_sinatra"
27
+
28
+ module SqAuth
29
+ @session_access = SqAuth::SqAuthAccess.new
30
+ def self.connect(*args, &block)
31
+ @session_access.connect(*args, &block)
32
+ end
33
+ def self.access
34
+ @session_access
35
+ end
36
+ def self.with_sq_auth(*args, &block)
37
+ @session_access.with_sq_auth(*args, &block)
38
+ end
39
+
40
+ def self.api_filter(roles, ok_proc, error_proc, options = {})
41
+ @session_access.api_filter(roles, SqAuth.access.project_name, ok_proc, error_proc, options)
42
+ end
43
+
44
+ def self.included(base)
45
+ base.send :include, InstanceMethods
46
+ end # self.included
47
+
48
+ module InstanceMethods
49
+ def access_for(*roles, &block)
50
+ SqAuth.with_sq_auth([*roles], SqAuth.access.project_name, {:binding => binding}, &block)
51
+ end
52
+ alias :draw_for :access_for
53
+
54
+ def accessed_by?(*roles)
55
+ SqAuth.access.sq_auth_filter([*roles])
56
+ end
57
+
58
+ def not_accessible_message
59
+ SqAuth.access.message_when_not_authenticated
60
+ end
61
+
62
+ def not_accessible_link(*roles)
63
+ SqAuth.access.draw_when_not_authenticated(roles)
64
+ end
65
+ end
66
+ end
67
+
68
+ include SqAuth
@@ -0,0 +1,30 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe SqAuth::SqAuthClient do
4
+ let(:client) {SqAuth::SqAuthClient.new}
5
+ let(:user1) { {name: "user1", ip: "234.24.23.1" } }
6
+ let(:user2) { {name: "user2", ip: "234.24.23.2" } }
7
+ let(:user3) { {name: "user3", ip: "234.24.23.3" } }
8
+
9
+ it "saves user session" do
10
+ SqAuth::SqAuthUser::BasicUser.stub(:current_user).and_return(user1)
11
+ client.create_session_for_current_user(Digest::MD5.digest(user1.to_s)).should_not == nil
12
+ end
13
+
14
+ it "checks for existance of user session" do
15
+ client.session_for(user2).should == nil
16
+ SqAuth::SqAuthUser::BasicUser.stub(:current_user).and_return(user3)
17
+ user3_session = client.create_session_for_current_user(Digest::MD5.digest(user3.to_s))
18
+ client.session_for_current_user.should == user3_session
19
+ end
20
+
21
+ it "sends check request to auth server" do
22
+ client.stub(:send_request).with(:check_connection).and_return("ok")
23
+ client.check_connection.should_not == nil
24
+ end
25
+
26
+ it "checks for role for sessioned user" do
27
+ client.stub(:send_request).with(:check_role, {sqauthsession: client.session_for_current_user, roles: ["role"], auth_name: "project", ip: "127.0.0.1"}).and_return("ok")
28
+ client.role_exist_for_current_user?("role", "project").should_not == nil
29
+ end
30
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe SqAuth::SqAuthRequest do
4
+ it 'convert hashes to http query strings' do
5
+ query_hash1 = {a: 1, b: "Hello", c: [123, "A B C", "+++"]}
6
+ query_string1 = "a=1&b=Hello&c[]=123&c[]=A%20B%20C&c[]=%2B%2B%2B"
7
+ SqAuth::SqAuthRequest.hash_to_query(query_hash1).should == query_string1
8
+ SqAuth::SqAuthRequest.hash_to_query({}).should == ""
9
+ SqAuth::SqAuthRequest.hash_to_query(nil).should == ""
10
+ SqAuth::SqAuthRequest.hash_to_query([1,2,3,4]).should == ""
11
+ end
12
+
13
+ it 'parse http responses' do
14
+ example_ok = Net::HTTPOK.new(1.1, '200', 'Ok')
15
+ example_ok.stub(:body).and_return("{\"a\": 1}")
16
+ SqAuth::SqAuthRequest.parse_response(example_ok).should == {status: "200", message: "Ok", data: {"a" => 1}}
17
+
18
+ example_error = Net::HTTPNotFound.new(1.1, '404', 'Page not found')
19
+ SqAuth::SqAuthRequest.parse_response(example_error).should == {status: "404", message: "Page not found"}
20
+
21
+ example_ok_with_not_json_body = Net::HTTPOK.new(1.1, '200', 'Ok')
22
+ example_ok.stub(:body).and_return("<title>Test</title><body>Body of the page</body>")
23
+ SqAuth::SqAuthRequest.parse_response(example_ok).should == {status: "200", message: "Ok", data: "<title>Test</title><body>Body of the page</body>"}
24
+ end
25
+
26
+ it 'should not fail if host unreachable' do
27
+ request = SqAuth::SqAuthRequest.new(host: "fake", path: "health", method: "get")
28
+ lambda {request.request({a: 1, b: 2})}.should_not raise_error
29
+ end
30
+
31
+ it 'send request to sq_auth server and parses response' do
32
+ request = SqAuth::SqAuthRequest.new(host: "localhost", path: "", method: "get")
33
+ example_ok = Net::HTTPOK.new(1.1, '200', 'Ok')
34
+ example_ok.stub(:body).and_return("{\"a\": 1}")
35
+ request.stub(:send_data).with(kind_of(Net::HTTP::Get)).and_return(example_ok)
36
+ request.request({}).should == {status: "200", message: "Ok", data: {"a" => 1}}
37
+ end
38
+
39
+
40
+ end
@@ -0,0 +1,24 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe SqAuth::SqAuthServer::BasicServer do
4
+ it 'should create request to custom sq_auth server once per server and send data to server by created request' do
5
+ host_options = {host: "localhost", port: 80}
6
+ interface = SqAuth::SqAuthServer::BasicServer::SERVER_INTERFACE[:check_connection]
7
+ mock_req = SqAuth::SqAuthRequest.new(host_options.merge({method: :get, path: "health"}))
8
+
9
+ # should create 2 requests: localhost/check_connection and localhost/check_role
10
+ SqAuth::SqAuthRequest.should_receive(:new).exactly(2).and_return(mock_req)
11
+ to_return = {status: "200", message: "Ok", data: {"a" => 1}}
12
+
13
+ # should send data 3 times by 2 request requests: localhost/check_connection, localhost/check_connection, and localhost/check_role
14
+ mock_req.should_receive(:request).exactly(3).and_return(to_return)
15
+
16
+ SqAuth::SqAuthServer::BasicServer.check_connection({}, host_options)[:data].should == {"a" => 1}
17
+ SqAuth::SqAuthServer::BasicServer.check_connection({}, host_options)[:data].should == {"a" => 1}
18
+ SqAuth::SqAuthServer::BasicServer.check_role({}, host_options)[:data].should == {"a" => 1}
19
+
20
+ SqAuth::SqAuthServer::BasicServer::SERVER_INTERFACE[:check_connection][:requests][host_options].should be_a_kind_of SqAuth::SqAuthRequest
21
+ SqAuth::SqAuthServer::BasicServer::SERVER_INTERFACE[:check_role][:requests][host_options].should be_a_kind_of SqAuth::SqAuthRequest
22
+ end
23
+
24
+ end
@@ -0,0 +1,3 @@
1
+ describe SqAuth::SqAuthSessions do
2
+
3
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path('spec/spec_helper')
2
+
3
+ describe SqAuth::SqAuthUser::BasicUser do
4
+
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe SqAuth do
4
+
5
+ end
@@ -0,0 +1 @@
1
+ require 'sq_auth'
data/sq_auth.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "sq_auth/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "sq_auth"
7
+ s.version = SqAuth::VERSION
8
+ s.authors = ["Leonid Krinitsyn"]
9
+ s.email = ["leonidkrn@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{SQ sevices authentication gem}
12
+ s.description = %q{SQ sevices authentication gem}
13
+
14
+ s.rubyforge_project = "sq_auth"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency 'rake'
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'sinatra'
24
+ end
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sq_auth
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.18
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Leonid Krinitsyn
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-05 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: sinatra
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: SQ sevices authentication gem
63
+ email:
64
+ - leonidkrn@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - .rspec
71
+ - Gemfile
72
+ - Rakefile
73
+ - examples/client.rb
74
+ - examples/server.rb
75
+ - lib/sq_auth.rb
76
+ - lib/sq_auth/sq_auth_access.rb
77
+ - lib/sq_auth/sq_auth_client.rb
78
+ - lib/sq_auth/sq_auth_helpers/sq_auth_helpers_dsl.rb
79
+ - lib/sq_auth/sq_auth_helpers/sq_auth_helpers_rails.rb
80
+ - lib/sq_auth/sq_auth_helpers/sq_auth_helpers_sinatra.rb
81
+ - lib/sq_auth/sq_auth_integration/sq_auth_action_controller.rb
82
+ - lib/sq_auth/sq_auth_integration/sq_auth_integration.rb
83
+ - lib/sq_auth/sq_auth_integration/sq_auth_rack.rb
84
+ - lib/sq_auth/sq_auth_integration/sq_auth_rack_protection.rb
85
+ - lib/sq_auth/sq_auth_integration/sq_auth_sinatra.rb
86
+ - lib/sq_auth/sq_auth_request.rb
87
+ - lib/sq_auth/sq_auth_server_interface/basic_server.rb
88
+ - lib/sq_auth/sq_auth_sessions.rb
89
+ - lib/sq_auth/sq_auth_user/basic_user.rb
90
+ - lib/sq_auth/sq_auth_user/rack_user.rb
91
+ - lib/sq_auth/sq_auth_utils.rb
92
+ - lib/sq_auth/version.rb
93
+ - spec/lib/sq_auth/sq_auth_client_spec.rb
94
+ - spec/lib/sq_auth/sq_auth_request_spec.rb
95
+ - spec/lib/sq_auth/sq_auth_server_interface/basic_server_spec.rb
96
+ - spec/lib/sq_auth/sq_auth_sessions_spec.rb
97
+ - spec/lib/sq_auth/sq_auth_user/basic_user_spec.rb
98
+ - spec/lib/sq_auth_spec.rb
99
+ - spec/spec_helper.rb
100
+ - sq_auth.gemspec
101
+ homepage: ''
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project: sq_auth
121
+ rubygems_version: 1.8.18
122
+ signing_key:
123
+ specification_version: 3
124
+ summary: SQ sevices authentication gem
125
+ test_files: []