parent
75ec64d94c
commit
7e40c11ca4
@ -0,0 +1,16 @@ |
||||
module OpenProject |
||||
module Authentication |
||||
module Strategies |
||||
module Warden |
||||
## |
||||
# This strategy is inserted after optional basic auth strategies to |
||||
# indicate that invalid basic auth credentials were provided. |
||||
class BasicAuthFailure < ::Warden::Strategies::BasicAuth |
||||
def authenticate_user(_username, _password) |
||||
nil # always fails |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,78 @@ |
||||
require 'warden/basic_auth' |
||||
|
||||
module OpenProject |
||||
module Authentication |
||||
module Strategies |
||||
module Warden |
||||
## |
||||
# Allows authentication via a singular set of basic auth credentials for admin access. |
||||
# |
||||
# The credentials must be configured in `config/configuration.yml` like this: |
||||
# |
||||
# production: |
||||
# authentication: |
||||
# global_basic_auth: |
||||
# user: admin |
||||
# password: 123456 |
||||
# |
||||
# The strategy will only be triggered when the configured user name is sent. |
||||
# Meaning that this strategy is skipped if a basic auth attempt involving any |
||||
# other user name is made. |
||||
class GlobalBasicAuth < ::Warden::Strategies::BasicAuth |
||||
def self.configuration |
||||
@configuration ||= configure! |
||||
end |
||||
|
||||
## |
||||
# Updates the configuration for this strategy. It's usually called only once, at startup. |
||||
# |
||||
# @param [Hash] config The configuration to be used. Must contain :user and :password. |
||||
# @raise [ArgumentError] Raises an error if the configured user name collides with the |
||||
# user name used for UserBasicAuth (apikey). |
||||
def self.configure!(config = openproject_config) |
||||
if config[:user] == UserBasicAuth.user |
||||
raise ArgumentError, "global user must not be '#{UserBasicAuth.user}'" |
||||
end |
||||
|
||||
@configuration = config |
||||
end |
||||
|
||||
## |
||||
# Reads the configuration for this strategy from OpenProject's `configuration.yml`. |
||||
def self.openproject_config |
||||
config = OpenProject::Configuration |
||||
%w(authentication global_basic_auth).inject(config) do |acc, key| |
||||
HashWithIndifferentAccess.new acc[key] |
||||
end |
||||
end |
||||
|
||||
def self.configuration? |
||||
user && password |
||||
end |
||||
|
||||
def self.user |
||||
configuration[:user] |
||||
end |
||||
|
||||
def self.password |
||||
configuration[:password] |
||||
end |
||||
|
||||
## |
||||
# Only valid if global basic auth is configured and tried. |
||||
def valid? |
||||
self.class.configuration? && super && username == self.class.user |
||||
end |
||||
|
||||
def authenticate_user(username, password) |
||||
if username == self.class.user && password == self.class.password |
||||
User.system.tap do |user| |
||||
user.admin = true |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,30 @@ |
||||
module OpenProject |
||||
module Authentication |
||||
module Strategies |
||||
module Warden |
||||
## |
||||
# Temporary strategy necessary as long as the OpenProject authentication has not been unified |
||||
# in terms of Warden strategies and is only locally applied to the API v3. |
||||
class Session < ::Warden::Strategies::Base |
||||
def valid? |
||||
session |
||||
end |
||||
|
||||
def authenticate! |
||||
user = user_id ? User.find(user_id) : User.anonymous |
||||
|
||||
success! user |
||||
end |
||||
|
||||
def user_id |
||||
Hash(session)['user_id'] |
||||
end |
||||
|
||||
def session |
||||
env['rack.session'] |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,34 @@ |
||||
require 'warden/basic_auth' |
||||
|
||||
module OpenProject |
||||
module Authentication |
||||
module Strategies |
||||
module Warden |
||||
## |
||||
# Allows users to authenticate using their API key via basic auth. |
||||
# Note that in order for a user to be able to generate one |
||||
# `Setting.rest_api_enabled` has to be `1`. |
||||
# |
||||
# The basic auth credentials are expected to contain the literal 'apikey' |
||||
# as the user name and the API key as the password. |
||||
class UserBasicAuth < ::Warden::Strategies::BasicAuth |
||||
def self.user |
||||
'apikey' |
||||
end |
||||
|
||||
def valid? |
||||
super && username == self.class.user |
||||
end |
||||
|
||||
def authenticate_user(_, api_key) |
||||
token(api_key).try(:user) |
||||
end |
||||
|
||||
def token(value) |
||||
Token.where(action: 'api', value: value).first |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,12 +0,0 @@ |
||||
module Warden |
||||
module Strategies |
||||
## |
||||
# This strategy is inserted after optional basic auth strategies to |
||||
# indicate that invalid basic auth credentials were provided. |
||||
class BasicAuthFailure < BasicAuth |
||||
def authenticate_user(_username, _password) |
||||
nil # always fails |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,62 +0,0 @@ |
||||
require 'warden/basic_auth' |
||||
|
||||
module Warden |
||||
module Strategies |
||||
## |
||||
# Allows authentication via a singular set of basic auth credentials for admin access. |
||||
# |
||||
# The credentials must be configured in `config/configuration.yml` like this: |
||||
# |
||||
# production: |
||||
# authentication: |
||||
# global_basic_auth: |
||||
# user: admin |
||||
# password: 123456 |
||||
# |
||||
# The strategy will only be triggered when the configured user name is sent. |
||||
# Meaning that this strategy is skipped if a basic auth attempt involving any |
||||
# other user name is made. |
||||
class GlobalBasicAuth < BasicAuth |
||||
def self.configuration |
||||
@configuration ||= configuration! |
||||
end |
||||
|
||||
def self.configuration! |
||||
path = %w(authentication global_basic_auth) |
||||
@configuration = path.inject(OpenProject::Configuration) { |acc, key| Hash(acc[key]) } |
||||
|
||||
if user == UserBasicAuth.user |
||||
raise ArgumentError, "global user must not be '#{UserBasicAuth.user}'" |
||||
end |
||||
|
||||
@configuration |
||||
end |
||||
|
||||
def self.configuration? |
||||
user && password |
||||
end |
||||
|
||||
def self.user |
||||
configuration['user'] |
||||
end |
||||
|
||||
def self.password |
||||
configuration['password'] |
||||
end |
||||
|
||||
## |
||||
# Only valid if global basic auth is configured and tried. |
||||
def valid? |
||||
self.class.configuration && super && username == self.class.user |
||||
end |
||||
|
||||
def authenticate_user(username, password) |
||||
if username == self.class.user && password == self.class.password |
||||
User.system.tap do |user| |
||||
user.admin = true |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,26 +0,0 @@ |
||||
module Warden |
||||
module Strategies |
||||
## |
||||
# Temporary strategy necessary as long as the OpenProject authentication has not been unified |
||||
# in terms of Warden strategies and is only locally applied to the API v3. |
||||
class Session < Base |
||||
def valid? |
||||
session |
||||
end |
||||
|
||||
def authenticate! |
||||
user = user_id ? User.find(user_id) : User.anonymous |
||||
|
||||
success! user |
||||
end |
||||
|
||||
def user_id |
||||
Hash(session)['user_id'] |
||||
end |
||||
|
||||
def session |
||||
env['rack.session'] |
||||
end |
||||
end |
||||
end |
||||
end |
@ -1,30 +0,0 @@ |
||||
require 'warden/basic_auth' |
||||
|
||||
module Warden |
||||
module Strategies |
||||
## |
||||
# Allows users to authenticate using their API key via basic auth. |
||||
# Note that in order for a user to be able to generate one |
||||
# `Setting.rest_api_enabled` has to be `1`. |
||||
# |
||||
# The basic auth credentials are expected to contain the literal 'apikey' |
||||
# as the user name and the API key as the password. |
||||
class UserBasicAuth < BasicAuth |
||||
def self.user |
||||
'apikey' |
||||
end |
||||
|
||||
def valid? |
||||
super && username == self.class.user |
||||
end |
||||
|
||||
def authenticate_user(_, api_key) |
||||
token(api_key).try(:user) |
||||
end |
||||
|
||||
def token(value) |
||||
Token.where(action: 'api', value: value).first |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,41 @@ |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2015 the OpenProject Foundation (OPF) |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License version 3. |
||||
# |
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: |
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang |
||||
# Copyright (C) 2010-2013 the ChiliProject Team |
||||
# |
||||
# This program is free software; you can redistribute it and/or |
||||
# modify it under the terms of the GNU General Public License |
||||
# as published by the Free Software Foundation; either version 2 |
||||
# of the License, or (at your option) any later version. |
||||
# |
||||
# This program is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with this program; if not, write to the Free Software |
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||
# |
||||
# See doc/COPYRIGHT.rdoc for more details. |
||||
#++ |
||||
|
||||
require 'spec_helper' |
||||
|
||||
describe OpenProject::Authentication::Strategies::Warden::GlobalBasicAuth do |
||||
it 'does not allow the UserBasicAuth user name' do |
||||
configuration = lambda do |
||||
user = OpenProject::Authentication::Strategies::Warden::UserBasicAuth.user |
||||
OpenProject::Authentication::Strategies::Warden::GlobalBasicAuth.configure!( |
||||
user: user, password: 'foo') |
||||
end |
||||
|
||||
expect(configuration).to raise_error(ArgumentError) |
||||
end |
||||
end |
Loading…
Reference in new issue