Skip to content

Instantly share code, notes, and snippets.

@darwinrc
Last active August 29, 2015 14:24
Show Gist options
  • Save darwinrc/2f03526f5a7ff8fea9c7 to your computer and use it in GitHub Desktop.
Save darwinrc/2f03526f5a7ff8fea9c7 to your computer and use it in GitHub Desktop.
Warden implementation in Lotus

apps/web/application.rb

controller.prepare do
        use YourApp::WardenImpl::WebManager
        include YourApp::WardenImpl::WardenHelper
        authentication_via :web_strategy
        auth_failure_to "/login"
        before :authenticate!    # run an authentication before callback
      end

apps/api/v1/application.rb

controller.prepare do
        use YourApp::WardenImpl::ApiManager
        include YourApp::WardenImpl::WardenHelper
        auth_failure_to "/api/v1/unauthenticated"
        
        before :authenticate! # run an authentication before callback
end

lib/your_app/warden_impl/web_manager.rb

module YourApp
  module WardenImpl
        class WebManager < ::Warden::Manager
          def initialize(app, options={})
            super(app, options)
            Warden::Strategies.add(:web_strategy, YourApp::WardenImpl::WebStrategy)
            config.scope_defaults :default, strategies: [:web_strategy], action: "login"
            config.failure_app = app

            Warden::Manager.before_failure do |env, opts|
              env['REQUEST_METHOD'] = "POST"
            end
          end
        end
      end
end

lib/your_app/warden_impl/web_strategy.rb

  module YourApp
      module WardenImpl
        class WebStrategy < ::Warden::Strategies::Base
          include Hashie::Extensions::SymbolizeKeys
          include Hashie::Extensions::DeepFind

          def request_params
            @request_params ||= Hashie.symbolize_keys!(params).extend(Hashie::Extensions::DeepFind)
          end

          def user_params(key)
            request_params.deep_find(key)
          end

          def valid?
            !user_params(:username).blank? && !user_params(:password).blank?
          end

          def authenticate!
            context.username = user_params(:username)
            context.password = client_params(:password)            
            authenticate_user.call(context) # This is an injected Interactor from Collective Idea ;)
            context.success? ? success!(context.output) : redirect!("/login?login_attempt=1")
          end
        end
      end
    end

lib/your_app/warden_impl/api_manager.rb

module YourApp
      module WardenImpl
        class ApiManager < ::Warden::Manager
          def initialize(app, options={})
            super(app, options)
            Warden::Strategies.add(:access_token, YourApp::WardenImpl::AccessTokenStrategy)
            config.scope_defaults :default, strategies: [:access_token]
            config.failure_app = app

            Warden::Manager.before_failure do |env, opts|
              env['REQUEST_METHOD'] = "POST"
            end
          end
        end
      end
    end

lib/your_app/warden_impl/access_token_strategy.rb

module YourApp
      module WardenImpl
        class AccessTokenStrategy < ::Warden::Strategies::Base
          def valid?
            access_token = request.env["HTTP_ACCESS_TOKEN"]
            access_token.is_a?(String) && !access_token.blank?
          end
          
          def authenticate!
            context.token = request.env["HTTP_ACCESS_TOKEN"]
            authenticate_access_token.call(context) #Another collectiveidea interactor!
            context.success? ? success!(context.output) : fail!("Could not log in")
          end
        end
      end
    end

lib/your_app/warden_impl/warden_helper.rb

module YourApp
      module WardenImpl
        module WardenHelper
          def self.included(base)
            base.extend ClassMethods
          end

          def authenticate!
            unless ignored_classes.include?(self.class)
              signin!
            end
          end

          def authenticated?
            request.env["warden"].authenticated?
          end

          def signin!
            request.env["warden"].authenticate!(strategy)
          rescue
            redirect_to auth_failure_path unless auth_failure_path.blank?
          end

          def logout!
            request.env["warden"].logout
          end

          def ignored_classes
            @ignored_classes ||= [].tap do |result|
              self.class.ignored_classes.each do |klass|
                result.push(klass)
              end
            end
          end

          def strategy
            @strategy = self.class.strategy!
          end

          def auth_failure_path
            @auth_failure_path = self.class.auth_failure_path
          end

          def current_user!
            request.env["warden"].user
          end

          module ClassMethods
            def ignore_authentication!
              class_eval do
                ignored_classes.push(self)
              end
            end

            def authentication_via(strategy)
              @strategy = strategy
            end

            def strategy!
              @strategy
            end

            def auth_failure_to(path)
              @auth_failure_path = path
            end

            def auth_failure_path
              @auth_failure_path
            end

            def ignored_classes
              @ignored_classes ||= []
            end
          end
        end
      end
    end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment