sq_auth 0.0.18

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.
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: []