tight-engine 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.
- checksums.yaml +7 -0
 - data/.gitignore +2 -0
 - data/LICENSE +20 -0
 - data/README.md +4 -0
 - data/Rakefile +15 -0
 - data/lib/tight/version.rb +3 -0
 - data/lib/tight-auth/access.rb +148 -0
 - data/lib/tight-auth/login/controller.rb +20 -0
 - data/lib/tight-auth/login/layout.slim +10 -0
 - data/lib/tight-auth/login/new.slim +37 -0
 - data/lib/tight-auth/login.rb +138 -0
 - data/lib/tight-auth/permissions.rb +180 -0
 - data/lib/tight-auth.rb +10 -0
 - data/test/auth_helper.rb +83 -0
 - data/test/test_padrino_access.rb +124 -0
 - data/test/test_padrino_auth.rb +38 -0
 - data/test/test_padrino_login.rb +76 -0
 - data/tight-engine.gemspec +23 -0
 - metadata +122 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 065ac37dc49f5b5e67ec4271bb92f71eee632e0f
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 72dfcdf5eae3c379407c7c698293515e59822db8
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 50b1e579488cad7dc14f878f8e2605e8d1837500de6e980aa175f14839693e7027d5df4dd078ef2d86a085e1714ee0f94988976cb39ba56b547dfad6a8b00ea9
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 0bc29fa1374faeb73b5949bc6f504f613fad53d39eac471350c69dfae7c6a78ae94e5429a6a927f3aba1eb4c6bb6255791c3112cd72c175f05f231448a13d3eb
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2013 Igor Bochkariov
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy of
         
     | 
| 
      
 6 
     | 
    
         
            +
            this software and associated documentation files (the "Software"), to deal in
         
     | 
| 
      
 7 
     | 
    
         
            +
            the Software without restriction, including without limitation the rights to
         
     | 
| 
      
 8 
     | 
    
         
            +
            use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
         
     | 
| 
      
 9 
     | 
    
         
            +
            the Software, and to permit persons to whom the Software is furnished to do so,
         
     | 
| 
      
 10 
     | 
    
         
            +
            subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 13 
     | 
    
         
            +
            copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
         
     | 
| 
      
 17 
     | 
    
         
            +
            FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
         
     | 
| 
      
 18 
     | 
    
         
            +
            COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
         
     | 
| 
      
 20 
     | 
    
         
            +
            CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    | 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            RAKE_ROOT = __FILE__
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rake'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'rake/testtask'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'bundler/gem_tasks'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'minitest/autorun'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Rake::TestTask.new(:test) do |test|
         
     | 
| 
      
 10 
     | 
    
         
            +
              test.libs << 'test'
         
     | 
| 
      
 11 
     | 
    
         
            +
              test.test_files = Dir['test/**/test_*.rb']
         
     | 
| 
      
 12 
     | 
    
         
            +
              test.verbose = true
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            task :default => :test
         
     | 
| 
         @@ -0,0 +1,148 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tight-auth/permissions'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tight
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Tight authorization module.
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @example
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   class Nifty::Application < Tight::Application
         
     | 
| 
      
 9 
     | 
    
         
            +
              #     # optional settings
         
     | 
| 
      
 10 
     | 
    
         
            +
              #     set :credentials_reader, :visitor # the name of getter method in helpers
         
     | 
| 
      
 11 
     | 
    
         
            +
              #     # required statement
         
     | 
| 
      
 12 
     | 
    
         
            +
              #     register Tight::Access
         
     | 
| 
      
 13 
     | 
    
         
            +
              #     # example persistance storage
         
     | 
| 
      
 14 
     | 
    
         
            +
              #     enable :sessions
         
     | 
| 
      
 15 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 16 
     | 
    
         
            +
              #
         
     | 
| 
      
 17 
     | 
    
         
            +
              #   # optional helpers
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   Nifty::Application.helpers do
         
     | 
| 
      
 19 
     | 
    
         
            +
              #     def visitor
         
     | 
| 
      
 20 
     | 
    
         
            +
              #       session[:visitor] ||= Visitor.guest_account
         
     | 
| 
      
 21 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 22 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              #   # example visitor model
         
     | 
| 
      
 25 
     | 
    
         
            +
              #   module Visitor
         
     | 
| 
      
 26 
     | 
    
         
            +
              #     extend self
         
     | 
| 
      
 27 
     | 
    
         
            +
              #     def guest_account
         
     | 
| 
      
 28 
     | 
    
         
            +
              #       OpenStruct.new(:role => :guest, :id => 1)
         
     | 
| 
      
 29 
     | 
    
         
            +
              #     end
         
     | 
| 
      
 30 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 31 
     | 
    
         
            +
              #
         
     | 
| 
      
 32 
     | 
    
         
            +
              #   # example controllers
         
     | 
| 
      
 33 
     | 
    
         
            +
              #   Nifty::Application.controller :public_area do
         
     | 
| 
      
 34 
     | 
    
         
            +
              #     set_access :*
         
     | 
| 
      
 35 
     | 
    
         
            +
              #     get(:index){ 'public content' }
         
     | 
| 
      
 36 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 37 
     | 
    
         
            +
              #   Nifty::Application.controller :members_area do
         
     | 
| 
      
 38 
     | 
    
         
            +
              #     set_access :member
         
     | 
| 
      
 39 
     | 
    
         
            +
              #     get(:index){ 'secret content' }
         
     | 
| 
      
 40 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 41 
     | 
    
         
            +
              #   Nifty::Application.controller :login do
         
     | 
| 
      
 42 
     | 
    
         
            +
              #     set_access :*
         
     | 
| 
      
 43 
     | 
    
         
            +
              #     get(:index){ session[:visitor] = OpenStruct.new(:role => :guest, :id => 1) }
         
     | 
| 
      
 44 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 45 
     | 
    
         
            +
              #
         
     | 
| 
      
 46 
     | 
    
         
            +
              module Access
         
     | 
| 
      
 47 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 48 
     | 
    
         
            +
                  def registered(app)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    included(app)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    app.default(:credentials_reader, :credentials)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    app.default(:access_errors, true)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    app.send :attr_reader, app.credentials_reader unless app.instance_methods.include?(app.credentials_reader)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    app.set :permissions, Permissions.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                    app.login_permissions if app.respond_to?(:login_permissions)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    app.before do
         
     | 
| 
      
 56 
     | 
    
         
            +
                      authorized? || error(403, '403 Forbidden')
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  def included(base)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    base.send(:include, InstanceMethods)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    base.extend(ClassMethods)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 67 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # Empties the list of permission.
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #
         
     | 
| 
      
 70 
     | 
    
         
            +
                  def reset_access!
         
     | 
| 
      
 71 
     | 
    
         
            +
                    permissions.clear!
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # Allows access to action with objects.
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #
         
     | 
| 
      
 77 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   # in application
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   set_access :*, :with => :login # allows everyone to interact with :login controller
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #   # in controller
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   App.controller :members_area do
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #     set_access :member # allows all members to access :members_area controller
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def set_access(*args)
         
     | 
| 
      
 86 
     | 
    
         
            +
                    options = args.extract_options!
         
     | 
| 
      
 87 
     | 
    
         
            +
                    options[:object] ||= Array(@_controller).first.to_s.singularize.to_sym if @_controller.present?
         
     | 
| 
      
 88 
     | 
    
         
            +
                    permissions.add(*args, options)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                module InstanceMethods
         
     | 
| 
      
 93 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # Checks if current visitor has access to current action with current controller.
         
     | 
| 
      
 95 
     | 
    
         
            +
                  #
         
     | 
| 
      
 96 
     | 
    
         
            +
                  def authorized?
         
     | 
| 
      
 97 
     | 
    
         
            +
                    access_action?
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 101 
     | 
    
         
            +
                  # Returns current visitor.
         
     | 
| 
      
 102 
     | 
    
         
            +
                  #
         
     | 
| 
      
 103 
     | 
    
         
            +
                  def access_subject
         
     | 
| 
      
 104 
     | 
    
         
            +
                    send settings.credentials_reader
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 108 
     | 
    
         
            +
                  # Checks if current visitor is one of the specified roles. Can accept a block.
         
     | 
| 
      
 109 
     | 
    
         
            +
                  #
         
     | 
| 
      
 110 
     | 
    
         
            +
                  def access_role?(*roles, &block)
         
     | 
| 
      
 111 
     | 
    
         
            +
                    settings.permissions.check(access_subject, :have => roles, &block)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 115 
     | 
    
         
            +
                  # Checks if current visitor is allowed to to the action with object. Can accept a block.
         
     | 
| 
      
 116 
     | 
    
         
            +
                  #
         
     | 
| 
      
 117 
     | 
    
         
            +
                  def access_action?(action = nil, object = nil, &block)
         
     | 
| 
      
 118 
     | 
    
         
            +
                    return true if response.status/100 == 4 && settings.access_errors
         
     | 
| 
      
 119 
     | 
    
         
            +
                    if respond_to?(:request) && action.nil? && object.nil?
         
     | 
| 
      
 120 
     | 
    
         
            +
                      object = request.controller
         
     | 
| 
      
 121 
     | 
    
         
            +
                      action = request.action
         
     | 
| 
      
 122 
     | 
    
         
            +
                      if object.nil? && action.present? && action.to_s.index('/')
         
     | 
| 
      
 123 
     | 
    
         
            +
                        object, action = request.env['PATH_INFO'].to_s.scan(/\/([^\/]*)/).map(&:first)
         
     | 
| 
      
 124 
     | 
    
         
            +
                      end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      object ||= :''
         
     | 
| 
      
 126 
     | 
    
         
            +
                      action ||= :index
         
     | 
| 
      
 127 
     | 
    
         
            +
                      object = object.to_sym
         
     | 
| 
      
 128 
     | 
    
         
            +
                      action = action.to_sym
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                    settings.permissions.check(access_subject, :allow => action, :with => object, &block)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 134 
     | 
    
         
            +
                  # Check if current visitor is allowed to interact with object by action. Can accept a block.
         
     | 
| 
      
 135 
     | 
    
         
            +
                  #
         
     | 
| 
      
 136 
     | 
    
         
            +
                  def access_object?(object = nil, action = nil, &block)
         
     | 
| 
      
 137 
     | 
    
         
            +
                    allow_action action, object, &block
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  ##
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # Populates the list of objects the current visitor is allowed to interact with.
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #
         
     | 
| 
      
 143 
     | 
    
         
            +
                  def access_objects(subject = access_subject, action = nil)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    settings.permissions.find_objects(subject, action)
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
              end
         
     | 
| 
      
 148 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tight
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Login
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Controller
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def self.included(base)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    base.get :index do
         
     | 
| 
      
 6 
     | 
    
         
            +
                      render :slim, :"new", :layout => :"layout", :views => File.dirname(__FILE__)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    end
         
     | 
| 
      
 8 
     | 
    
         
            +
                    base.post :index do
         
     | 
| 
      
 9 
     | 
    
         
            +
                      if authenticate
         
     | 
| 
      
 10 
     | 
    
         
            +
                        restore_location
         
     | 
| 
      
 11 
     | 
    
         
            +
                      else
         
     | 
| 
      
 12 
     | 
    
         
            +
                        params.delete 'password'
         
     | 
| 
      
 13 
     | 
    
         
            +
                        flash.now[:error] = 'Wrong password'
         
     | 
| 
      
 14 
     | 
    
         
            +
                        render :slim, :"new", :layout => :"layout", :views => File.dirname(__FILE__)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            doctype html
         
     | 
| 
      
 2 
     | 
    
         
            +
            html
         
     | 
| 
      
 3 
     | 
    
         
            +
              head
         
     | 
| 
      
 4 
     | 
    
         
            +
                meta charset="utf-8"
         
     | 
| 
      
 5 
     | 
    
         
            +
                meta name="robots" content="noindex"
         
     | 
| 
      
 6 
     | 
    
         
            +
                title Padrino::Login
         
     | 
| 
      
 7 
     | 
    
         
            +
                link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/2.3.2/css/bootstrap.min.css"
         
     | 
| 
      
 8 
     | 
    
         
            +
              body
         
     | 
| 
      
 9 
     | 
    
         
            +
                .container.login style='width: 287px'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  = yield
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            h3
         
     | 
| 
      
 2 
     | 
    
         
            +
              | Login
         
     | 
| 
      
 3 
     | 
    
         
            +
              br
         
     | 
| 
      
 4 
     | 
    
         
            +
              small
         
     | 
| 
      
 5 
     | 
    
         
            +
                a href=url('/') = request.env['HTTP_HOST']
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            form.form-horizontal.well action=''
         
     | 
| 
      
 8 
     | 
    
         
            +
              - [:error, :warning, :success, :notice].each do |type|
         
     | 
| 
      
 9 
     | 
    
         
            +
                - next  if flash[type].blank?
         
     | 
| 
      
 10 
     | 
    
         
            +
                .alert.alert-message class=('alert-' + (type == :notice ? :info : type).to_s) data-alert=true
         
     | 
| 
      
 11 
     | 
    
         
            +
                  = flash[type]
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              legend Social
         
     | 
| 
      
 14 
     | 
    
         
            +
              .control-group
         
     | 
| 
      
 15 
     | 
    
         
            +
                a href=url('/oauth/google')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  img src='/images/social/google.png'
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              legend Obsolete
         
     | 
| 
      
 19 
     | 
    
         
            +
              .control-group
         
     | 
| 
      
 20 
     | 
    
         
            +
                .input-prepend
         
     | 
| 
      
 21 
     | 
    
         
            +
                  span.add-on
         
     | 
| 
      
 22 
     | 
    
         
            +
                    i.icon-envelope
         
     | 
| 
      
 23 
     | 
    
         
            +
                  input type=:text name=:email value=params[:email] placeholder='email'
         
     | 
| 
      
 24 
     | 
    
         
            +
              .control-group
         
     | 
| 
      
 25 
     | 
    
         
            +
                .input-prepend
         
     | 
| 
      
 26 
     | 
    
         
            +
                  span.add-on
         
     | 
| 
      
 27 
     | 
    
         
            +
                    i.icon-lock
         
     | 
| 
      
 28 
     | 
    
         
            +
                  input type=:password name=:password value=params[:password] placeholder='password'
         
     | 
| 
      
 29 
     | 
    
         
            +
              .control-group
         
     | 
| 
      
 30 
     | 
    
         
            +
                input.btn.btn-primary.pull-right type=:submit Log in
         
     | 
| 
      
 31 
     | 
    
         
            +
                - if settings.login_bypass
         
     | 
| 
      
 32 
     | 
    
         
            +
                  label.checkbox
         
     | 
| 
      
 33 
     | 
    
         
            +
                    | Bypass
         
     | 
| 
      
 34 
     | 
    
         
            +
                    input type=:checkbox name=:bypass value='Bypass'
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            small
         
     | 
| 
      
 37 
     | 
    
         
            +
              a href=url('/login/reset_password') Forgot password?
         
     | 
| 
         @@ -0,0 +1,138 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tight-auth/login/controller'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tight
         
     | 
| 
      
 4 
     | 
    
         
            +
              ##
         
     | 
| 
      
 5 
     | 
    
         
            +
              # Tight authentication module.
         
     | 
| 
      
 6 
     | 
    
         
            +
              #
         
     | 
| 
      
 7 
     | 
    
         
            +
              # @example
         
     | 
| 
      
 8 
     | 
    
         
            +
              #   class Nifty::Application < Tight::Application
         
     | 
| 
      
 9 
     | 
    
         
            +
              #     # optional settings
         
     | 
| 
      
 10 
     | 
    
         
            +
              #     set :session_key, "visitor_id"       # visitor key name in session storage, defaults to "_login_#{app.app_name}")
         
     | 
| 
      
 11 
     | 
    
         
            +
              #     set :login_model, :visitor          # model name for visitor storage, defaults to :account, must be constantizable
         
     | 
| 
      
 12 
     | 
    
         
            +
              #     set :credentials_accessor, :visitor # the name of setter/getter method in helpers, defaults to :credentials
         
     | 
| 
      
 13 
     | 
    
         
            +
              #     enable :login_bypass                # enables or disables login bypass in development mode, defaults to disable
         
     | 
| 
      
 14 
     | 
    
         
            +
              #     set :login_url, '/sign/in'          # sets the utl to be redirected to if not logged in and in restricted area, defaults to '/login'
         
     | 
| 
      
 15 
     | 
    
         
            +
              #     disable :login_permissions          # sets initial login permissions, defaults to { set_access(:*, :allow => :*, :with => :login) }
         
     | 
| 
      
 16 
     | 
    
         
            +
              #     disable :login_controller           # disables default login controller to show an example of the custom one
         
     | 
| 
      
 17 
     | 
    
         
            +
              #
         
     | 
| 
      
 18 
     | 
    
         
            +
              #     # required statement
         
     | 
| 
      
 19 
     | 
    
         
            +
              #     register Tight::Login
         
     | 
| 
      
 20 
     | 
    
         
            +
              #     # example persistance storage
         
     | 
| 
      
 21 
     | 
    
         
            +
              #     enable :sessions
         
     | 
| 
      
 22 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              #   TODO: example controllers
         
     | 
| 
      
 25 
     | 
    
         
            +
              #
         
     | 
| 
      
 26 
     | 
    
         
            +
              module Login
         
     | 
| 
      
 27 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def registered(app)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    warn 'Tight::Login must be registered before Tight::Access' if app.respond_to?(:set_access)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    included(app)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    setup_storage(app)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    setup_controller(app)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    app.before do
         
     | 
| 
      
 34 
     | 
    
         
            +
                      log_in if authorization_required?
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  def included(base)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    base.send(:include, InstanceMethods)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  private
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  def setup_storage(app)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    app.default(:session_key, "_login_#{app.app_name}")
         
     | 
| 
      
 46 
     | 
    
         
            +
                    app.default(:login_model, :account)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    app.default(:credentials_accessor, :credentials)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    app.send :attr_reader, app.credentials_accessor unless app.instance_methods.include?(app.credentials_accessor)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    app.send :attr_writer, app.credentials_accessor unless app.instance_methods.include?(:"#{app.credentials_accessor}=")
         
     | 
| 
      
 50 
     | 
    
         
            +
                    app.default(:login_bypass, false)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def setup_controller(app)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    app.default(:login_url, '/login')
         
     | 
| 
      
 55 
     | 
    
         
            +
                    app.default(:login_permissions) { set_access(:*, :allow => :*, :with => :login) }
         
     | 
| 
      
 56 
     | 
    
         
            +
                    app.default(:login_controller, true)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    app.controller(:login) { include Controller } if app.login_controller
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                module InstanceMethods
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # Returns the model used to authenticate visitors.
         
     | 
| 
      
 63 
     | 
    
         
            +
                  def login_model
         
     | 
| 
      
 64 
     | 
    
         
            +
                    @login_model ||= settings.login_model.to_s.classify.constantize
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  # Authenticates the visitor.
         
     | 
| 
      
 68 
     | 
    
         
            +
                  def authenticate
         
     | 
| 
      
 69 
     | 
    
         
            +
                    resource = login_model.authenticate(:email => params[:email], :password => params[:password])
         
     | 
| 
      
 70 
     | 
    
         
            +
                    resource ||= login_model.authenticate(:bypass => true) if settings.login_bypass && params[:bypass]
         
     | 
| 
      
 71 
     | 
    
         
            +
                    save_credentials(resource)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  # Checks if the visitor is authenticated.
         
     | 
| 
      
 75 
     | 
    
         
            +
                  def logged_in?
         
     | 
| 
      
 76 
     | 
    
         
            +
                    !!(send(settings.credentials_accessor) || restore_credentials)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  # Looks for authorization routine and calls it to check if the visitor is authorized.
         
     | 
| 
      
 80 
     | 
    
         
            +
                  def unauthorized?
         
     | 
| 
      
 81 
     | 
    
         
            +
                    respond_to?(:authorized?) && !authorized?
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  # Checks if the current location needs the visitor to be authorized.
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def authorization_required?
         
     | 
| 
      
 86 
     | 
    
         
            +
                    if logged_in?
         
     | 
| 
      
 87 
     | 
    
         
            +
                      if unauthorized?
         
     | 
| 
      
 88 
     | 
    
         
            +
                        # 403 Forbidden, provided credentials were successfully
         
     | 
| 
      
 89 
     | 
    
         
            +
                        # authenticated but the credentials still do not grant
         
     | 
| 
      
 90 
     | 
    
         
            +
                        # the client permission to access the resource
         
     | 
| 
      
 91 
     | 
    
         
            +
                        error 403, '403 Forbidden'
         
     | 
| 
      
 92 
     | 
    
         
            +
                      else
         
     | 
| 
      
 93 
     | 
    
         
            +
                        false
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
                    else
         
     | 
| 
      
 96 
     | 
    
         
            +
                      unauthorized?
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  # Logs the visitor in using redirect to login page url.
         
     | 
| 
      
 101 
     | 
    
         
            +
                  def log_in
         
     | 
| 
      
 102 
     | 
    
         
            +
                    login_url = settings.login_url
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if request.env['PATH_INFO'] != login_url
         
     | 
| 
      
 104 
     | 
    
         
            +
                      save_location
         
     | 
| 
      
 105 
     | 
    
         
            +
                      # 302 Found
         
     | 
| 
      
 106 
     | 
    
         
            +
                      redirect url(login_url) 
         
     | 
| 
      
 107 
     | 
    
         
            +
                      # 401 Unauthorized, authentication is required and
         
     | 
| 
      
 108 
     | 
    
         
            +
                      # has not yet been provided
         
     | 
| 
      
 109 
     | 
    
         
            +
                      error 401, '401 Unauthorized'
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  # Saves credentials in session.
         
     | 
| 
      
 114 
     | 
    
         
            +
                  def save_credentials(resource)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    session[settings.session_key] = resource.respond_to?(:id) ? resource.id : resource
         
     | 
| 
      
 116 
     | 
    
         
            +
                    send(:"#{settings.credentials_accessor}=", resource)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                  # Restores credentials from session using visitor model.
         
     | 
| 
      
 120 
     | 
    
         
            +
                  def restore_credentials
         
     | 
| 
      
 121 
     | 
    
         
            +
                    resource = login_model.authenticate(:id => session[settings.session_key])
         
     | 
| 
      
 122 
     | 
    
         
            +
                    send(:"#{settings.credentials_accessor}=", resource)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  # Redirects back to saved location or '/'
         
     | 
| 
      
 126 
     | 
    
         
            +
                  def restore_location
         
     | 
| 
      
 127 
     | 
    
         
            +
                    redirect session.delete(:return_to) || url('/')
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  # Saves location to session for following redirect in case of successful authentication.
         
     | 
| 
      
 131 
     | 
    
         
            +
                  def save_location
         
     | 
| 
      
 132 
     | 
    
         
            +
                    uri = env['REQUEST_URI'] || url(env['PATH_INFO'])
         
     | 
| 
      
 133 
     | 
    
         
            +
                    return if uri.blank? || uri.match(/\.css$|\.js$|\.png$/)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    session[:return_to] = "#{ENV['RACK_BASE_URI']}#{uri}"
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,180 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tight
         
     | 
| 
      
 2 
     | 
    
         
            +
              ##
         
     | 
| 
      
 3 
     | 
    
         
            +
              # Class to store and check permissions used in Padrino::Access.
         
     | 
| 
      
 4 
     | 
    
         
            +
              #
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Permissions
         
     | 
| 
      
 6 
     | 
    
         
            +
                ##
         
     | 
| 
      
 7 
     | 
    
         
            +
                # Initializes new permissions storage.
         
     | 
| 
      
 8 
     | 
    
         
            +
                #
         
     | 
| 
      
 9 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 10 
     | 
    
         
            +
                #   permissions = Permissions.new
         
     | 
| 
      
 11 
     | 
    
         
            +
                #
         
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 13 
     | 
    
         
            +
                  clear!
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                ##
         
     | 
| 
      
 17 
     | 
    
         
            +
                # Clears permit records and action cache.
         
     | 
| 
      
 18 
     | 
    
         
            +
                #
         
     | 
| 
      
 19 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 20 
     | 
    
         
            +
                #   permissions.clear!
         
     | 
| 
      
 21 
     | 
    
         
            +
                #
         
     | 
| 
      
 22 
     | 
    
         
            +
                def clear!
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @permits = {}
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @actions = {}
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                ##
         
     | 
| 
      
 28 
     | 
    
         
            +
                # Adds a permission record to storage.
         
     | 
| 
      
 29 
     | 
    
         
            +
                #
         
     | 
| 
      
 30 
     | 
    
         
            +
                # @param [Symbol || Object] subject
         
     | 
| 
      
 31 
     | 
    
         
            +
                #   permit subject
         
     | 
| 
      
 32 
     | 
    
         
            +
                # @param [Hash] options
         
     | 
| 
      
 33 
     | 
    
         
            +
                #   permit attributes
         
     | 
| 
      
 34 
     | 
    
         
            +
                # @param [Symbol] options[:allow] || options[:action]
         
     | 
| 
      
 35 
     | 
    
         
            +
                #   what action to allow with objects
         
     | 
| 
      
 36 
     | 
    
         
            +
                # @param [Symbol] options[:with] || options[:object]
         
     | 
| 
      
 37 
     | 
    
         
            +
                #   with what objects allow specified action
         
     | 
| 
      
 38 
     | 
    
         
            +
                #
         
     | 
| 
      
 39 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 40 
     | 
    
         
            +
                #   permissions.add :robots, :allow => :protect, :object => :humans
         
     | 
| 
      
 41 
     | 
    
         
            +
                #   permissions.add @bender, :allow => :kill, :object => :humans
         
     | 
| 
      
 42 
     | 
    
         
            +
                #
         
     | 
| 
      
 43 
     | 
    
         
            +
                def add(*args)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @actions = {}
         
     | 
| 
      
 45 
     | 
    
         
            +
                  options = args.extract_options!
         
     | 
| 
      
 46 
     | 
    
         
            +
                  action, object = action_and_object(options)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  object_type = detect_type(object)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  args.each{ |subject| merge(subject, action, object_type) }
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                ##
         
     | 
| 
      
 52 
     | 
    
         
            +
                # Checks if permission record exists. Returns a boolean or yield a block.
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                # @param [Object] subject
         
     | 
| 
      
 55 
     | 
    
         
            +
                #   performer of an action
         
     | 
| 
      
 56 
     | 
    
         
            +
                # @param [Hash] options
         
     | 
| 
      
 57 
     | 
    
         
            +
                #   attributes to check
         
     | 
| 
      
 58 
     | 
    
         
            +
                # @param [Symbol] options[:have]
         
     | 
| 
      
 59 
     | 
    
         
            +
                #   check if the subject has a role
         
     | 
| 
      
 60 
     | 
    
         
            +
                # @param [Symbol] options[:allow] || options[:action]
         
     | 
| 
      
 61 
     | 
    
         
            +
                #   check if the subject is allowed to perform the action
         
     | 
| 
      
 62 
     | 
    
         
            +
                # @param [Symbol] options[:with] || options[:object]
         
     | 
| 
      
 63 
     | 
    
         
            +
                #   check if the subject is allowed to interact with the subject
         
     | 
| 
      
 64 
     | 
    
         
            +
                # @param [Proc]
         
     | 
| 
      
 65 
     | 
    
         
            +
                #   optional block to yield if the action is allowed
         
     | 
| 
      
 66 
     | 
    
         
            +
                #
         
     | 
| 
      
 67 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 68 
     | 
    
         
            +
                #   # check if @bender have role :robots
         
     | 
| 
      
 69 
     | 
    
         
            +
                #   permissions.check @bender, :have => :robots # => true
         
     | 
| 
      
 70 
     | 
    
         
            +
                #   # check if @bender is allowed to kill :humans
         
     | 
| 
      
 71 
     | 
    
         
            +
                #   permissions.check @bender, :allow => :kill, :object => :humans # => true
         
     | 
| 
      
 72 
     | 
    
         
            +
                #   # check if @bender is allowed to kill :humans and yield a block
         
     | 
| 
      
 73 
     | 
    
         
            +
                #   permissions.check @bender, :allow => :kill, :object => :humans do
         
     | 
| 
      
 74 
     | 
    
         
            +
                #     @bender.kill_all! :humans
         
     | 
| 
      
 75 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 76 
     | 
    
         
            +
                #
         
     | 
| 
      
 77 
     | 
    
         
            +
                def check(subject, options)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  case
         
     | 
| 
      
 79 
     | 
    
         
            +
                  when options[:have]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    check_role(subject, options[:have])
         
     | 
| 
      
 81 
     | 
    
         
            +
                  else
         
     | 
| 
      
 82 
     | 
    
         
            +
                    check_action(subject, *action_and_object(options))
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end && (block_given? ? yield : true)
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                ##
         
     | 
| 
      
 87 
     | 
    
         
            +
                # Populates and returns the list of objects available to the subject.
         
     | 
| 
      
 88 
     | 
    
         
            +
                #
         
     | 
| 
      
 89 
     | 
    
         
            +
                # @param [Object] subject
         
     | 
| 
      
 90 
     | 
    
         
            +
                #   the subject to be checked for actions
         
     | 
| 
      
 91 
     | 
    
         
            +
                #
         
     | 
| 
      
 92 
     | 
    
         
            +
                def find_objects(subject, target_action=nil)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  find_actions(subject).inject([]) do |all,(action,objects)|
         
     | 
| 
      
 94 
     | 
    
         
            +
                    all |= objects if target_action.nil? || action == target_action || action == :*
         
     | 
| 
      
 95 
     | 
    
         
            +
                    all
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                private
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                # Merges a list of new permits into permissions storage.
         
     | 
| 
      
 102 
     | 
    
         
            +
                def merge(subject, actions, object_type)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  subject_id = detect_id(subject)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  @permits[subject_id] ||= {}
         
     | 
| 
      
 105 
     | 
    
         
            +
                  Array(actions).each do |action|
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @permits[subject_id][action] ||= []
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @permits[subject_id][action] |= [object_type]
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                # Checks if the subject has the role.
         
     | 
| 
      
 112 
     | 
    
         
            +
                def check_role(subject, roles)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  if subject.respond_to?(:role)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    Array(roles).include?(subject.role)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  else
         
     | 
| 
      
 116 
     | 
    
         
            +
                    false
         
     | 
| 
      
 117 
     | 
    
         
            +
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                # Checks if the subject is allowed to perform the action with the object.
         
     | 
| 
      
 121 
     | 
    
         
            +
                def check_action(subject, action, object)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  actions = find_actions(subject)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  objects = actions && (Array(actions[action]) | Array(actions[:*]))
         
     | 
| 
      
 124 
     | 
    
         
            +
                  objects && (objects & [:*, detect_type(object)]).any?
         
     | 
| 
      
 125 
     | 
    
         
            +
                end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                # Finds all permits for the subject. Caches the permits in @actions.
         
     | 
| 
      
 128 
     | 
    
         
            +
                #   find_actions(@bender) # => { :kill => { :humans }, :drink => { :booze }, :* => { :login } }
         
     | 
| 
      
 129 
     | 
    
         
            +
                def find_actions(subject)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  subject_id = detect_id(subject)
         
     | 
| 
      
 131 
     | 
    
         
            +
                  return @actions[subject_id] if @actions[subject_id]
         
     | 
| 
      
 132 
     | 
    
         
            +
                  actions = @permits[subject_id] || {}
         
     | 
| 
      
 133 
     | 
    
         
            +
                  if subject.respond_to?(:role) && (role_actions = @permits[subject.role.to_sym])
         
     | 
| 
      
 134 
     | 
    
         
            +
                    actions.merge!(role_actions){ |_,left,right| Array(left)|Array(right) }
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                  if public_actions = @permits[:*]
         
     | 
| 
      
 137 
     | 
    
         
            +
                    actions.merge!(public_actions){ |_,left,right| Array(left)|Array(right) }
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  @actions[subject_id] = actions
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                # Returns object type.
         
     | 
| 
      
 143 
     | 
    
         
            +
                #   detect_type :humans # => :human
         
     | 
| 
      
 144 
     | 
    
         
            +
                #   detect_type 'foobar' # => 'foobar'
         
     | 
| 
      
 145 
     | 
    
         
            +
                def detect_type(object)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  case object
         
     | 
| 
      
 147 
     | 
    
         
            +
                  when Symbol
         
     | 
| 
      
 148 
     | 
    
         
            +
                    object.to_s.singularize.to_sym
         
     | 
| 
      
 149 
     | 
    
         
            +
                  else
         
     | 
| 
      
 150 
     | 
    
         
            +
                    object
         
     | 
| 
      
 151 
     | 
    
         
            +
                  end
         
     | 
| 
      
 152 
     | 
    
         
            +
                end
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
                # Returns parametrized subject.
         
     | 
| 
      
 155 
     | 
    
         
            +
                #   detect_id :robots               # => :robots
         
     | 
| 
      
 156 
     | 
    
         
            +
                #   detect_id sluggable_ar_resource # => 'Sluggable-resource-slug'
         
     | 
| 
      
 157 
     | 
    
         
            +
                #   detect_id some_resource_with_id # => '4'
         
     | 
| 
      
 158 
     | 
    
         
            +
                #   detect_id generic_object        # => "<Object:0x00001234>"
         
     | 
| 
      
 159 
     | 
    
         
            +
                def detect_id(subject)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  case
         
     | 
| 
      
 161 
     | 
    
         
            +
                  when Symbol === subject
         
     | 
| 
      
 162 
     | 
    
         
            +
                    subject
         
     | 
| 
      
 163 
     | 
    
         
            +
                  when subject.respond_to?(:to_param)
         
     | 
| 
      
 164 
     | 
    
         
            +
                    subject.to_param
         
     | 
| 
      
 165 
     | 
    
         
            +
                  when subject.respond_to?(:id)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    subject.id.to_s
         
     | 
| 
      
 167 
     | 
    
         
            +
                  else
         
     | 
| 
      
 168 
     | 
    
         
            +
                    "#{subject}"
         
     | 
| 
      
 169 
     | 
    
         
            +
                  end
         
     | 
| 
      
 170 
     | 
    
         
            +
                end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                # Utility function to extract action and object from options. Defaults to [:*, :*]
         
     | 
| 
      
 173 
     | 
    
         
            +
                #   action_and_object(:allow => :kill, :object => :humans)    # => [:kill, :humans]
         
     | 
| 
      
 174 
     | 
    
         
            +
                #   action_and_object(:action => :romance, :with => :mutants) # => [:romance, :mutants]
         
     | 
| 
      
 175 
     | 
    
         
            +
                #   action_and_object({})                                     # => [:*, :*]
         
     | 
| 
      
 176 
     | 
    
         
            +
                def action_and_object(options)
         
     | 
| 
      
 177 
     | 
    
         
            +
                  [options[:allow] || options[:action] || :*, options[:with] || options[:object] || :*]
         
     | 
| 
      
 178 
     | 
    
         
            +
                end
         
     | 
| 
      
 179 
     | 
    
         
            +
              end
         
     | 
| 
      
 180 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/tight-auth.rb
    ADDED
    
    
    
        data/test/auth_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,83 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ENV['RACK_ENV'] = 'test'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'padrino-core'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'tight-auth'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'minitest/autorun'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'rack/test'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module TightLogger
         
     | 
| 
      
 9 
     | 
    
         
            +
              attr_accessor :io
         
     | 
| 
      
 10 
     | 
    
         
            +
              def self.io
         
     | 
| 
      
 11 
     | 
    
         
            +
                @io ||= StringIO.new
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Padrino::Logger::Config[:test] = { :log_level => :devel, :stream => TightLogger.io }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            class Minitest::Spec
         
     | 
| 
      
 18 
     | 
    
         
            +
              include Rack::Test::Methods
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              def mock_app(base=Padrino::Application, &block)
         
     | 
| 
      
 21 
     | 
    
         
            +
                @app = Sinatra.new(base, &block)
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def app
         
     | 
| 
      
 25 
     | 
    
         
            +
                Rack::Lint.new(@app)
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              def set_access(*args)
         
     | 
| 
      
 29 
     | 
    
         
            +
                @app.set_access(*args)
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              def allow(subject = nil, path = '/')
         
     | 
| 
      
 33 
     | 
    
         
            +
                @app.fake_session[:visitor] = nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                get "/login/#{subject.id}" if subject
         
     | 
| 
      
 35 
     | 
    
         
            +
                get path
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_equal 200, status, caller.first.to_s
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def deny(subject = nil, path = '/')
         
     | 
| 
      
 40 
     | 
    
         
            +
                @app.fake_session[:visitor] = nil
         
     | 
| 
      
 41 
     | 
    
         
            +
                get "/login/#{subject.id}" if subject
         
     | 
| 
      
 42 
     | 
    
         
            +
                get path
         
     | 
| 
      
 43 
     | 
    
         
            +
                assert_equal 403, status, caller.first.to_s
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              def status
         
     | 
| 
      
 47 
     | 
    
         
            +
                response.status
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              def body
         
     | 
| 
      
 51 
     | 
    
         
            +
                response.body
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              def response
         
     | 
| 
      
 55 
     | 
    
         
            +
                last_response
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            module Character
         
     | 
| 
      
 60 
     | 
    
         
            +
              extend self
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              def authenticate(credentials)
         
     | 
| 
      
 63 
     | 
    
         
            +
                case
         
     | 
| 
      
 64 
     | 
    
         
            +
                when credentials[:email] && credentials[:password]
         
     | 
| 
      
 65 
     | 
    
         
            +
                  target = all.find{ |resource| resource.id.to_s == credentials[:email] }
         
     | 
| 
      
 66 
     | 
    
         
            +
                  target.name.gsub(/[^A-Z]/,'') == credentials[:password] ? target : nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                when credentials.has_key?(:id)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  all.find{ |resource| resource.id == credentials[:id] }
         
     | 
| 
      
 69 
     | 
    
         
            +
                else
         
     | 
| 
      
 70 
     | 
    
         
            +
                  false
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def all
         
     | 
| 
      
 75 
     | 
    
         
            +
                @all = [
         
     | 
| 
      
 76 
     | 
    
         
            +
                  OpenStruct.new(:id => :bender,   :name => 'Bender Bending Rodriguez', :role => :robots  ),
         
     | 
| 
      
 77 
     | 
    
         
            +
                  OpenStruct.new(:id => :leela,    :name => 'Turanga Leela',            :role => :mutants ),
         
     | 
| 
      
 78 
     | 
    
         
            +
                  OpenStruct.new(:id => :fry,      :name => 'Philip J. Fry',            :role => :humans  ),
         
     | 
| 
      
 79 
     | 
    
         
            +
                  OpenStruct.new(:id => :ami,      :name => 'Amy Wong',                 :role => :humans  ),
         
     | 
| 
      
 80 
     | 
    
         
            +
                  OpenStruct.new(:id => :zoidberg, :name => 'Dr. John A. Zoidberg',     :role => :lobsters),
         
     | 
| 
      
 81 
     | 
    
         
            +
                ]
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,124 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('../auth_helper', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe "Tight::Access" do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before do
         
     | 
| 
      
 5 
     | 
    
         
            +
                mock_app do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  set :credentials_reader, :visitor
         
     | 
| 
      
 7 
     | 
    
         
            +
                  register Tight::Access
         
     | 
| 
      
 8 
     | 
    
         
            +
                  set_access :*, :allow => :login
         
     | 
| 
      
 9 
     | 
    
         
            +
                  set :users, Character.all
         
     | 
| 
      
 10 
     | 
    
         
            +
                  get(:login, :with => :id) do
         
     | 
| 
      
 11 
     | 
    
         
            +
                    user = settings.users.find{ |user| user.id.to_s == params[:id] }
         
     | 
| 
      
 12 
     | 
    
         
            +
                    self.send(:"#{settings.credentials_reader}=", user)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  get(:index){ 'foo' }
         
     | 
| 
      
 15 
     | 
    
         
            +
                  get(:bend){ 'bend' }
         
     | 
| 
      
 16 
     | 
    
         
            +
                  get(:drink){ 'bend' }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  get(:subject){ self.send(settings.credentials_reader).inspect }
         
     | 
| 
      
 18 
     | 
    
         
            +
                  get(:stop_partying){ 'stop partying' }
         
     | 
| 
      
 19 
     | 
    
         
            +
                  controller :surface do
         
     | 
| 
      
 20 
     | 
    
         
            +
                    get(:live) { 'live on the surface' }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  controller :sewers do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    get(:live) { 'live in the sewers' }
         
     | 
| 
      
 24 
     | 
    
         
            +
                    get(:visit) { 'visit the sewers' }
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  set :fake_session, {}
         
     | 
| 
      
 27 
     | 
    
         
            +
                  helpers do
         
     | 
| 
      
 28 
     | 
    
         
            +
                    def visitor
         
     | 
| 
      
 29 
     | 
    
         
            +
                      settings.fake_session[:visitor]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
                    def visitor=(user)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      settings.fake_session[:visitor] = user
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                Character.all.each do |user|
         
     | 
| 
      
 37 
     | 
    
         
            +
                  instance_variable_set :"@#{user.id}", user
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              it 'should register with authorization module' do
         
     | 
| 
      
 42 
     | 
    
         
            +
                assert @app.respond_to? :set_access
         
     | 
| 
      
 43 
     | 
    
         
            +
                assert_kind_of Tight::Permissions, @app.permissions
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              it 'should properly detect access subject' do
         
     | 
| 
      
 47 
     | 
    
         
            +
                set_access :*
         
     | 
| 
      
 48 
     | 
    
         
            +
                get '/login/ami'
         
     | 
| 
      
 49 
     | 
    
         
            +
                get '/subject'
         
     | 
| 
      
 50 
     | 
    
         
            +
                assert_equal @ami.inspect, body
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              it 'should reset access properly' do
         
     | 
| 
      
 54 
     | 
    
         
            +
                set_access :*
         
     | 
| 
      
 55 
     | 
    
         
            +
                allow
         
     | 
| 
      
 56 
     | 
    
         
            +
                @app.reset_access!
         
     | 
| 
      
 57 
     | 
    
         
            +
                deny
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              it 'should set group access' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                # only humans should be allowed on TV
         
     | 
| 
      
 62 
     | 
    
         
            +
                set_access :humans
         
     | 
| 
      
 63 
     | 
    
         
            +
                allow @fry
         
     | 
| 
      
 64 
     | 
    
         
            +
                deny @bender
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              it 'should set individual access' do
         
     | 
| 
      
 68 
     | 
    
         
            +
                # only Fry should be allowed to romance Leela
         
     | 
| 
      
 69 
     | 
    
         
            +
                set_access @fry
         
     | 
| 
      
 70 
     | 
    
         
            +
                allow @fry
         
     | 
| 
      
 71 
     | 
    
         
            +
                deny @ami
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              it 'should set mixed individual and group access' do
         
     | 
| 
      
 75 
     | 
    
         
            +
                # only humans and Leela should be allowed on the surface
         
     | 
| 
      
 76 
     | 
    
         
            +
                set_access :humans
         
     | 
| 
      
 77 
     | 
    
         
            +
                set_access @leela
         
     | 
| 
      
 78 
     | 
    
         
            +
                allow @fry
         
     | 
| 
      
 79 
     | 
    
         
            +
                allow @leela
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              it 'should set action-specific access' do
         
     | 
| 
      
 83 
     | 
    
         
            +
                # bender should be allowed to bend, and he's denied to stop partying
         
     | 
| 
      
 84 
     | 
    
         
            +
                set_access @bender, :allow => :bend
         
     | 
| 
      
 85 
     | 
    
         
            +
                set_access @fry, :allow => :stop_partying
         
     | 
| 
      
 86 
     | 
    
         
            +
                allow @bender, '/bend'
         
     | 
| 
      
 87 
     | 
    
         
            +
                deny @bender, '/stop_partying'
         
     | 
| 
      
 88 
     | 
    
         
            +
                allow @fry, '/stop_partying'
         
     | 
| 
      
 89 
     | 
    
         
            +
                deny @fry, '/bend'
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              it 'should set multiple action' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                # bender should be allowed to bend and drink
         
     | 
| 
      
 94 
     | 
    
         
            +
                set_access @bender, :allow => [:drink, :bend]
         
     | 
| 
      
 95 
     | 
    
         
            +
                allow @bender, '/drink'
         
     | 
| 
      
 96 
     | 
    
         
            +
                allow @bender, '/bend'
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
              it 'should set object-specific access' do
         
     | 
| 
      
 100 
     | 
    
         
            +
                # only humans and Leela should be allowed to live on the surface
         
     | 
| 
      
 101 
     | 
    
         
            +
                # only mutants should be allowed to live in the sewers though humans can visit
         
     | 
| 
      
 102 
     | 
    
         
            +
                set_access :humans, :allow => :live, :with => :surface
         
     | 
| 
      
 103 
     | 
    
         
            +
                set_access :mutants, :allow => :live, :with => :sewers
         
     | 
| 
      
 104 
     | 
    
         
            +
                set_access @leela, :allow => :live, :with => :surface
         
     | 
| 
      
 105 
     | 
    
         
            +
                set_access :humans, :allow => :visit, :with => :sewers
         
     | 
| 
      
 106 
     | 
    
         
            +
                allow @fry, '/surface/live'
         
     | 
| 
      
 107 
     | 
    
         
            +
                deny @fry, '/sewers/live'
         
     | 
| 
      
 108 
     | 
    
         
            +
                allow @fry, '/sewers/visit'
         
     | 
| 
      
 109 
     | 
    
         
            +
                allow @leela, '/surface/live'
         
     | 
| 
      
 110 
     | 
    
         
            +
                allow @leela, '/sewers/live'
         
     | 
| 
      
 111 
     | 
    
         
            +
              end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
              it 'should detect object when setting access from controller' do
         
     | 
| 
      
 114 
     | 
    
         
            +
                # only humans and lobsters should have binocular vision
         
     | 
| 
      
 115 
     | 
    
         
            +
                @app.controller :binocular do
         
     | 
| 
      
 116 
     | 
    
         
            +
                  set_access :humans, :lobsters
         
     | 
| 
      
 117 
     | 
    
         
            +
                  get(:vision) { 'binocular vision' }
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
                deny @fry, '/'
         
     | 
| 
      
 120 
     | 
    
         
            +
                allow @fry, '/binocular/vision'
         
     | 
| 
      
 121 
     | 
    
         
            +
                allow @zoidberg, '/binocular/vision'
         
     | 
| 
      
 122 
     | 
    
         
            +
                deny @leela, '/binocular/vision'
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('../auth_helper', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Account = Character
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            describe "Tight::Auth" do
         
     | 
| 
      
 6 
     | 
    
         
            +
              before do
         
     | 
| 
      
 7 
     | 
    
         
            +
                mock_app do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  enable :sessions
         
     | 
| 
      
 9 
     | 
    
         
            +
                  register Tight::Login
         
     | 
| 
      
 10 
     | 
    
         
            +
                  register Tight::Access
         
     | 
| 
      
 11 
     | 
    
         
            +
                  get(:robot_area){ 'robot_area' }
         
     | 
| 
      
 12 
     | 
    
         
            +
                  set_access :robots, :allow => :robot_area
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it 'should login and access play nicely together' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                get '/robot_area'
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert_equal 302, status
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                post '/login', :email => :bender, :password => 'BBR'
         
     | 
| 
      
 21 
     | 
    
         
            +
                get '/robot_area'
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                post '/login', :email => :leela, :password => 'TL'
         
     | 
| 
      
 25 
     | 
    
         
            +
                get '/robot_area'
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_equal 403, status
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              it 'should whine if the order is wrong' do
         
     | 
| 
      
 30 
     | 
    
         
            +
                out, err = capture_io do
         
     | 
| 
      
 31 
     | 
    
         
            +
                  mock_app do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    register Tight::Access
         
     | 
| 
      
 33 
     | 
    
         
            +
                    register Tight::Login
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_match /must be registered before/, err
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require File.expand_path('../auth_helper', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'padrino-helpers'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe "Tight::Access" do
         
     | 
| 
      
 5 
     | 
    
         
            +
              before do
         
     | 
| 
      
 6 
     | 
    
         
            +
                mock_app do
         
     | 
| 
      
 7 
     | 
    
         
            +
                  set :credentials_accessor, :visitor
         
     | 
| 
      
 8 
     | 
    
         
            +
                  set :login_model, :character
         
     | 
| 
      
 9 
     | 
    
         
            +
                  enable :sessions
         
     | 
| 
      
 10 
     | 
    
         
            +
                  register Tight::Login
         
     | 
| 
      
 11 
     | 
    
         
            +
                  get(:index){ 'index' }
         
     | 
| 
      
 12 
     | 
    
         
            +
                  get(:restricted){ 'secret' }
         
     | 
| 
      
 13 
     | 
    
         
            +
                  helpers do
         
     | 
| 
      
 14 
     | 
    
         
            +
                    def authorized?
         
     | 
| 
      
 15 
     | 
    
         
            +
                      return !['/restricted'].include?(request.env['PATH_INFO']) unless visitor
         
     | 
| 
      
 16 
     | 
    
         
            +
                      case 
         
     | 
| 
      
 17 
     | 
    
         
            +
                      when visitor.id == :bender
         
     | 
| 
      
 18 
     | 
    
         
            +
                        true
         
     | 
| 
      
 19 
     | 
    
         
            +
                      else
         
     | 
| 
      
 20 
     | 
    
         
            +
                        false            
         
     | 
| 
      
 21 
     | 
    
         
            +
                      end
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
                Character.all.each do |user|
         
     | 
| 
      
 26 
     | 
    
         
            +
                  instance_variable_set :"@#{user.id}", user
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              it 'should pass unrestricted area' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                get '/'
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              it 'should be redirected from restricted area to login page' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                get '/restricted'
         
     | 
| 
      
 37 
     | 
    
         
            +
                assert_equal 302, status
         
     | 
| 
      
 38 
     | 
    
         
            +
                get response.location
         
     | 
| 
      
 39 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 40 
     | 
    
         
            +
                assert_match /<form .*<input .*/, body
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              it 'should not be able to authenticate with wrong password' do
         
     | 
| 
      
 44 
     | 
    
         
            +
                post '/login', :email => :bender, :password => '123'
         
     | 
| 
      
 45 
     | 
    
         
            +
                assert_equal 200, status
         
     | 
| 
      
 46 
     | 
    
         
            +
                assert_match 'Wrong password', body
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              it 'should be able to authenticate with email and password' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                post '/login', :email => :bender, :password => 'BBR'
         
     | 
| 
      
 51 
     | 
    
         
            +
                assert_equal 302, status
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              it 'should be redirected back' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                get '/restricted'
         
     | 
| 
      
 56 
     | 
    
         
            +
                post response.location, :email => :bender, :password => 'BBR'
         
     | 
| 
      
 57 
     | 
    
         
            +
                assert_match /\/restricted$/, response.location
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              it 'should be redirected to root if no location was saved' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                post '/login', :email => :bender, :password => 'BBR'
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert_match /\/$/, response.location
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              it 'should be allowed in restricted area after logging in' do
         
     | 
| 
      
 66 
     | 
    
         
            +
                post '/login', :email => :bender, :password => 'BBR'
         
     | 
| 
      
 67 
     | 
    
         
            +
                get '/restricted'
         
     | 
| 
      
 68 
     | 
    
         
            +
                assert_equal 'secret', body
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              it 'should not be allowed in restricted area after logging in an account lacking privileges' do
         
     | 
| 
      
 72 
     | 
    
         
            +
                post '/login', :email => :leela, :password => 'TL'
         
     | 
| 
      
 73 
     | 
    
         
            +
                get '/restricted'
         
     | 
| 
      
 74 
     | 
    
         
            +
                assert_equal 403, status
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $LOAD_PATH << File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tight/version'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 5 
     | 
    
         
            +
              spec.name          = 'tight-engine'
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.version       = Tight::VERSION
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.description   = 'Tight engine for Swift CMS'
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.summary       = 'A tight engine for a swift content management system'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              spec.authors       = ['Igor Bochkariov']
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.email         = ['ujifgc@gmail.com']
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.homepage      = 'https://github.com/ujifgc/tight-engine'
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.license       = 'MIT'
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              spec.require_paths = ['lib']
         
     | 
| 
      
 16 
     | 
    
         
            +
              spec.files         = `git ls-files`.split($/)
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.test_files    = spec.files.grep(%r{^test/})
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              spec.add_development_dependency 'bundler', '~> 1.3'
         
     | 
| 
      
 20 
     | 
    
         
            +
              spec.add_development_dependency 'rake'
         
     | 
| 
      
 21 
     | 
    
         
            +
              spec.add_development_dependency 'minitest'
         
     | 
| 
      
 22 
     | 
    
         
            +
              spec.add_development_dependency 'padrino-core'
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,122 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: tight-engine
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Igor Bochkariov
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2014-03-12 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '1.3'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '1.3'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: minitest
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: padrino-core
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            description: Tight engine for Swift CMS
         
     | 
| 
      
 70 
     | 
    
         
            +
            email:
         
     | 
| 
      
 71 
     | 
    
         
            +
            - ujifgc@gmail.com
         
     | 
| 
      
 72 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 73 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 74 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 75 
     | 
    
         
            +
            files:
         
     | 
| 
      
 76 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 77 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 78 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 79 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 80 
     | 
    
         
            +
            - lib/tight-auth.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - lib/tight-auth/access.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - lib/tight-auth/login.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/tight-auth/login/controller.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - lib/tight-auth/login/layout.slim
         
     | 
| 
      
 85 
     | 
    
         
            +
            - lib/tight-auth/login/new.slim
         
     | 
| 
      
 86 
     | 
    
         
            +
            - lib/tight-auth/permissions.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib/tight/version.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - test/auth_helper.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - test/test_padrino_access.rb
         
     | 
| 
      
 90 
     | 
    
         
            +
            - test/test_padrino_auth.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - test/test_padrino_login.rb
         
     | 
| 
      
 92 
     | 
    
         
            +
            - tight-engine.gemspec
         
     | 
| 
      
 93 
     | 
    
         
            +
            homepage: https://github.com/ujifgc/tight-engine
         
     | 
| 
      
 94 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 95 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 96 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 97 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 98 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 99 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 100 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 101 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 102 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 103 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 104 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 105 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 106 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 107 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 108 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 109 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 110 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 111 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 112 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 113 
     | 
    
         
            +
            rubygems_version: 2.2.2
         
     | 
| 
      
 114 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 115 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 116 
     | 
    
         
            +
            summary: A tight engine for a swift content management system
         
     | 
| 
      
 117 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 118 
     | 
    
         
            +
            - test/auth_helper.rb
         
     | 
| 
      
 119 
     | 
    
         
            +
            - test/test_padrino_access.rb
         
     | 
| 
      
 120 
     | 
    
         
            +
            - test/test_padrino_auth.rb
         
     | 
| 
      
 121 
     | 
    
         
            +
            - test/test_padrino_login.rb
         
     | 
| 
      
 122 
     | 
    
         
            +
            has_rdoc: 
         
     |