From 514ada7cc9af49117d6cf63966925e21d137933e Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 20 Jul 2022 03:09:04 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/ci/rules.gitlab-ci.yml | 7 + .gitlab/ci/vendored-gems.gitlab-ci.yml | 8 + Gemfile | 2 +- Gemfile.lock | 14 +- app/models/container_registry/event.rb | 11 +- doc/administration/index.md | 1 - doc/administration/troubleshooting/debug.md | 17 +- doc/administration/troubleshooting/index.md | 4 +- doc/api/project_level_variables.md | 2 +- doc/api/users.md | 3 +- spec/models/container_registry/event_spec.rb | 38 +- vendor/gems/omniauth_crowd/.gitlab-ci.yml | 30 ++ vendor/gems/omniauth_crowd/Gemfile | 4 + vendor/gems/omniauth_crowd/Gemfile.lock | 74 ++++ vendor/gems/omniauth_crowd/LICENSE.txt | 20 + vendor/gems/omniauth_crowd/README.md | 52 +++ vendor/gems/omniauth_crowd/Rakefile | 12 + .../lib/omniauth/strategies/crowd.rb | 97 +++++ .../strategies/crowd/configuration.rb | 110 +++++ .../strategies/crowd/crowd_validator.rb | 186 +++++++++ .../gems/omniauth_crowd/lib/omniauth_crowd.rb | 1 + .../lib/omniauth_crowd/version.rb | 5 + .../omniauth_crowd/omniauth_crowd.gemspec | 28 ++ .../omniauth_crowd/spec/fixtures/groups.xml | 8 + .../omniauth_crowd/spec/fixtures/session.xml | 8 + .../omniauth_crowd/spec/fixtures/success.xml | 11 + .../spec/omniauth/strategies/crowd_spec.rb | 387 ++++++++++++++++++ .../gems/omniauth_crowd/spec/spec_helper.rb | 14 + 28 files changed, 1125 insertions(+), 29 deletions(-) create mode 100644 vendor/gems/omniauth_crowd/.gitlab-ci.yml create mode 100644 vendor/gems/omniauth_crowd/Gemfile create mode 100644 vendor/gems/omniauth_crowd/Gemfile.lock create mode 100644 vendor/gems/omniauth_crowd/LICENSE.txt create mode 100644 vendor/gems/omniauth_crowd/README.md create mode 100644 vendor/gems/omniauth_crowd/Rakefile create mode 100755 vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd.rb create mode 100644 vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/configuration.rb create mode 100755 vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/crowd_validator.rb create mode 100644 vendor/gems/omniauth_crowd/lib/omniauth_crowd.rb create mode 100644 vendor/gems/omniauth_crowd/lib/omniauth_crowd/version.rb create mode 100644 vendor/gems/omniauth_crowd/omniauth_crowd.gemspec create mode 100644 vendor/gems/omniauth_crowd/spec/fixtures/groups.xml create mode 100644 vendor/gems/omniauth_crowd/spec/fixtures/session.xml create mode 100644 vendor/gems/omniauth_crowd/spec/fixtures/success.xml create mode 100755 vendor/gems/omniauth_crowd/spec/omniauth/strategies/crowd_spec.rb create mode 100644 vendor/gems/omniauth_crowd/spec/spec_helper.rb diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index 5d551c2564b..93790f431dd 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -1481,6 +1481,13 @@ changes: ["vendor/gems/ipynbdiff/**/*"] - <<: *if-merge-request-labels-run-all-rspec +.vendor:rules:omniauth_crowd: + rules: + - <<: *if-merge-request + changes: ["vendor/gems/omniauth_crowd/**/*"] + - <<: *if-merge-request-labels-run-all-rspec + + .vendor:rules:omniauth-gitlab: rules: - <<: *if-merge-request diff --git a/.gitlab/ci/vendored-gems.gitlab-ci.yml b/.gitlab/ci/vendored-gems.gitlab-ci.yml index 1f89186ed94..8596d770a87 100644 --- a/.gitlab/ci/vendored-gems.gitlab-ci.yml +++ b/.gitlab/ci/vendored-gems.gitlab-ci.yml @@ -14,6 +14,14 @@ vendor ipynbdiff: include: vendor/gems/ipynbdiff/.gitlab-ci.yml strategy: depend +vendor omniauth_crowd: + extends: + - .vendor:rules:omniauth_crowd + needs: [] + trigger: + include: vendor/gems/omniauth_crowd/.gitlab-ci.yml + strategy: depend + vendor omniauth-gitlab: extends: - .vendor:rules:omniauth-gitlab diff --git a/Gemfile b/Gemfile index 722324d812e..71cd2609b3a 100644 --- a/Gemfile +++ b/Gemfile @@ -51,7 +51,7 @@ gem 'omniauth-oauth2-generic', '~> 0.2.2' gem 'omniauth-saml', '~> 1.10' gem 'omniauth-shibboleth', '~> 1.3.0' gem 'omniauth-twitter', '~> 1.4' -gem 'omniauth_crowd', '~> 2.4.0' +gem 'omniauth_crowd', '~> 2.4.0', path: 'vendor/gems/omniauth_crowd' # See vendor/gems/omniauth_crowd/README.md gem 'omniauth-authentiq', '~> 0.3.3' gem 'gitlab-omniauth-openid-connect', '~> 0.9.0', require: 'omniauth_openid_connect' gem 'omniauth-salesforce', '~> 1.0.5' diff --git a/Gemfile.lock b/Gemfile.lock index 379f4a5d1cf..6ccdd090ee9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -31,6 +31,14 @@ PATH omniauth (~> 1.0) omniauth-oauth2 (~> 1.7.1) +PATH + remote: vendor/gems/omniauth_crowd + specs: + omniauth_crowd (2.4.0) + activesupport + nokogiri (>= 1.4.4) + omniauth (~> 1.0, < 3) + GEM remote: https://rubygems.org/ specs: @@ -915,10 +923,6 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - omniauth_crowd (2.4.0) - activesupport - nokogiri (>= 1.4.4) - omniauth (~> 1.0) open4 (1.3.4) openid_connect (1.3.0) activemodel @@ -1652,7 +1656,7 @@ DEPENDENCIES omniauth-saml (~> 1.10) omniauth-shibboleth (~> 1.3.0) omniauth-twitter (~> 1.4) - omniauth_crowd (~> 2.4.0) + omniauth_crowd (~> 2.4.0)! org-ruby (~> 0.9.12) pact (~> 1.12) parallel (~> 1.19) diff --git a/app/models/container_registry/event.rb b/app/models/container_registry/event.rb index 47d21d21afd..d4075e1ff1b 100644 --- a/app/models/container_registry/event.rb +++ b/app/models/container_registry/event.rb @@ -6,6 +6,7 @@ module ContainerRegistry ALLOWED_ACTIONS = %w(push delete).freeze PUSH_ACTION = 'push' + DELETE_ACTION = 'delete' EVENT_TRACKING_CATEGORY = 'container_registry:notification' attr_reader :event @@ -41,6 +42,10 @@ module ContainerRegistry event['target'].has_key?('tag') end + def target_digest? + event['target'].has_key?('digest') + end + def target_repository? !target_tag? && event['target'].has_key?('repository') end @@ -53,6 +58,10 @@ module ContainerRegistry PUSH_ACTION == action end + def action_delete? + DELETE_ACTION == action + end + def container_repository_exists? return unless container_registry_path @@ -74,7 +83,7 @@ module ContainerRegistry def update_project_statistics return unless supported? - return unless target_tag? + return unless target_tag? || (action_delete? && target_digest?) return unless project Rails.cache.delete(project.root_ancestor.container_repositories_size_cache_key) diff --git a/doc/administration/index.md b/doc/administration/index.md index de4f2f5e926..4565c0a8e00 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -207,7 +207,6 @@ Learn how to install, configure, update, and maintain your GitLab instance. ## Troubleshooting -- [Debugging tips](troubleshooting/debug.md): Tips to debug problems when things go wrong. - [Log system](logs.md): Where to look for logs. - [Sidekiq Troubleshooting](troubleshooting/sidekiq.md): Debug when Sidekiq appears hung and is not processing jobs. - [Troubleshooting Elasticsearch](troubleshooting/elasticsearch.md) diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md index 2ea79a15e6e..d5019f1aa4a 100644 --- a/doc/administration/troubleshooting/debug.md +++ b/doc/administration/troubleshooting/debug.md @@ -1,14 +1,11 @@ --- -stage: Systems -group: Distribution -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +redirect_to: '../reference_architectures/troubleshooting.md' +remove_date: '2022-10-19' --- -# Debugging tips **(FREE SELF)** +This document was moved to [another location](../reference_architectures/troubleshooting.md). -Sometimes things don't work the way they should. Here are some tips on debugging issues out -in production. - -## More information - -- [Debugging Stuck Ruby Processes](https://newrelic.com/blog/best-practices/debugging-stuck-ruby-processes-what-to-do-before-you-kill-9) + + + + diff --git a/doc/administration/troubleshooting/index.md b/doc/administration/troubleshooting/index.md index 495c2870ca6..7fe731bda66 100644 --- a/doc/administration/troubleshooting/index.md +++ b/doc/administration/troubleshooting/index.md @@ -21,8 +21,10 @@ installation. - [Linux cheat sheet](linux_cheat_sheet.md) - [Parsing GitLab logs with `jq`](log_parsing.md) - [Diagnostics tools](diagnostics_tools.md) -- [Debugging tips](debug.md) - [Tracing requests with correlation ID](tracing_correlation_id.md) +Some feature documentation pages also have a troubleshooting section at the end +that you can check for feature-specific help. + If you need a testing environment to troubleshoot, see the [apps for a testing environment](test_environments.md). diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md index 4205e6699fe..81bb4a26614 100644 --- a/doc/api/project_level_variables.md +++ b/doc/api/project_level_variables.md @@ -170,5 +170,5 @@ This parameter is used for filtering by attributes, such as `environment_scope`. Example usage: ```shell -curl --request DELETE --globoff --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1?filter[environment_scope]=production" +curl --globoff --header "PRIVATE-TOKEN: " "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1?filter[environment_scope]=production" ``` diff --git a/doc/api/users.md b/doc/api/users.md index 75561f8e33d..06c0fadbbbf 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -57,8 +57,7 @@ NOTE: Username search is case insensitive. In addition, you can filter users based on the states `blocked` and `active`. -It does not support `active=false` or `blocked=false`. The list of billable users -is the total number of users minus the blocked users. +It does not support `active=false` or `blocked=false`. ```plaintext GET /users?active=true diff --git a/spec/models/container_registry/event_spec.rb b/spec/models/container_registry/event_spec.rb index e0194a07f46..799d9d4fd1c 100644 --- a/spec/models/container_registry/event_spec.rb +++ b/spec/models/container_registry/event_spec.rb @@ -40,16 +40,18 @@ RSpec.describe ContainerRegistry::Event do subject(:handle!) { described_class.new(raw_event).handle! } - it 'enqueues a project statistics update' do - expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:container_registry_size]) + shared_examples 'event with project statistics update' do + it 'enqueues a project statistics update' do + expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:container_registry_size]) - handle! - end + handle! + end - it 'clears the cache for the namespace container repositories size' do - expect(Rails.cache).to receive(:delete).with(group.container_repositories_size_cache_key) + it 'clears the cache for the namespace container repositories size' do + expect(Rails.cache).to receive(:delete).with(group.container_repositories_size_cache_key) - handle! + handle! + end end shared_examples 'event without project statistics update' do @@ -60,10 +62,32 @@ RSpec.describe ContainerRegistry::Event do end end + it_behaves_like 'event with project statistics update' + context 'with no target tag' do let(:target) { super().without('tag') } it_behaves_like 'event without project statistics update' + + context 'with a target digest' do + let(:target) { super().merge('digest' => 'abc123') } + + it_behaves_like 'event without project statistics update' + end + + context 'with a delete action' do + let(:action) { 'delete' } + + context 'without a target digest' do + it_behaves_like 'event without project statistics update' + end + + context 'with a target digest' do + let(:target) { super().merge('digest' => 'abc123') } + + it_behaves_like 'event with project statistics update' + end + end end context 'with an unsupported action' do diff --git a/vendor/gems/omniauth_crowd/.gitlab-ci.yml b/vendor/gems/omniauth_crowd/.gitlab-ci.yml new file mode 100644 index 00000000000..98e686db4e3 --- /dev/null +++ b/vendor/gems/omniauth_crowd/.gitlab-ci.yml @@ -0,0 +1,30 @@ +workflow: + rules: + - if: $CI_MERGE_REQUEST_ID + +.rspec: + cache: + key: omniauth-gitlab-ruby + paths: + - vendor/gems/omniauth_crowd/vendor/ruby + before_script: + - cd vendor/gems/omniauth_crowd + - ruby -v # Print out ruby version for debugging + - gem install bundler --no-document # Bundler is not installed with the image + - bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby + - bundle config set with 'development' + - bundle install -j $(nproc) + script: + - bundle exec rspec + +rspec-2.6: + image: "ruby:2.6" + extends: .rspec + +rspec-2.7: + image: "ruby:2.7" + extends: .rspec + +rspec-3.0: + image: "ruby:3.0" + extends: .rspec diff --git a/vendor/gems/omniauth_crowd/Gemfile b/vendor/gems/omniauth_crowd/Gemfile new file mode 100644 index 00000000000..e2305d86b8d --- /dev/null +++ b/vendor/gems/omniauth_crowd/Gemfile @@ -0,0 +1,4 @@ +source 'http://rubygems.org' + +# Specify your gem's dependencies in omniauth-github.gemspec +gemspec diff --git a/vendor/gems/omniauth_crowd/Gemfile.lock b/vendor/gems/omniauth_crowd/Gemfile.lock new file mode 100644 index 00000000000..0ac781e9948 --- /dev/null +++ b/vendor/gems/omniauth_crowd/Gemfile.lock @@ -0,0 +1,74 @@ +PATH + remote: . + specs: + omniauth_crowd (2.4.0) + activesupport + nokogiri (>= 1.4.4) + omniauth (~> 1.0, < 3) + +GEM + remote: http://rubygems.org/ + specs: + activesupport (5.0.0.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (~> 0.7) + minitest (~> 5.1) + tzinfo (~> 1.1) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + concurrent-ruby (1.0.5) + crack (0.4.3) + safe_yaml (~> 1.0.0) + diff-lcs (1.2.5) + hashdiff (0.3.6) + hashie (3.4.3) + i18n (0.8.1) + mini_portile2 (2.1.0) + minitest (5.10.1) + nokogiri (1.6.8.1) + mini_portile2 (~> 2.1.0) + omniauth (1.3.1) + hashie (>= 1.2, < 4) + rack (>= 1.0, < 3) + public_suffix (3.0.0) + rack (1.6.4) + rack-test (0.6.3) + rack (>= 1.0) + rake (10.5.0) + rexml (3.2.5) + rspec (3.0.0) + rspec-core (~> 3.0.0) + rspec-expectations (~> 3.0.0) + rspec-mocks (~> 3.0.0) + rspec-core (3.0.4) + rspec-support (~> 3.0.0) + rspec-expectations (3.0.4) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.0.0) + rspec-mocks (3.0.4) + rspec-support (~> 3.0.0) + rspec-support (3.0.4) + safe_yaml (1.0.4) + thread_safe (0.3.6) + tzinfo (1.2.2) + thread_safe (~> 0.1) + webmock (3.0.1) + addressable (>= 2.3.6) + crack (>= 0.3.2) + hashdiff + +PLATFORMS + ruby + +DEPENDENCIES + bundler (> 1.0.0) + omniauth_crowd! + rack + rack-test + rake + rexml (~> 3.2.5) + rspec (~> 3.0.0) + webmock (~> 3.0.0) + +BUNDLED WITH + 2.3.15 diff --git a/vendor/gems/omniauth_crowd/LICENSE.txt b/vendor/gems/omniauth_crowd/LICENSE.txt new file mode 100644 index 00000000000..463a011fbaf --- /dev/null +++ b/vendor/gems/omniauth_crowd/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2011 Rob Di Marco + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/gems/omniauth_crowd/README.md b/vendor/gems/omniauth_crowd/README.md new file mode 100644 index 00000000000..01d8119b15d --- /dev/null +++ b/vendor/gems/omniauth_crowd/README.md @@ -0,0 +1,52 @@ +# omniauth_crowd + +This is fork of [omniauth_crowd](https://github.com/robdimarco/omniauth_crowd) to support: + +1. OmniAuth v1 and v2. OmniAuth v2 disables GET requests by default + and defaults to POST. GitLab already has patched v1 to use POST, + but other dependencies need to be updated: + https://gitlab.com/gitlab-org/gitlab/-/issues/30073. +2. We may deprecate this library entirely in the future: + https://gitlab.com/gitlab-org/gitlab/-/issues/366212 + +The omniauth_crowd library is an OmniAuth provider that supports authentication against Atlassian Crowd REST apis. + +[![Build Status](https://travis-ci.org/robdimarco/omniauth_crowd.svg?branch=master)](https://travis-ci.org/robdimarco/omniauth_crowd) + +## Helpful links + +* [Documentation](http://github.com/robdimarco/omniauth_crow) +* [OmniAuth](https://github.com/intridea/omniauth/) +* [Atlassian Crowd](http://www.atlassian.com/software/crowd/) +* [Atlassian Crowd REST API](http://confluence.atlassian.com/display/CROWDDEV/Crowd+REST+APIs) + +## Install and use + +### 1. Add the OmniAuth Crowd REST plugin to your Gemfile + + gem 'omniauth', '>= 1.0.0' # We depend on this + gem "omniauth_crowd" + +### 2. You will need to configure OmniAuth to use your crowd authentication. This is generally done in Rails in the config/initializers/omniauth.rb with... + + Rails.application.config.middleware.use OmniAuth::Builder do + provider :crowd, :crowd_server_url=>"https://crowd.mycompanyname.com/crowd", :application_name=>"app", :application_password=>"password" + end + +You will need to supply the correct server URL, application name and password + +## Contributing to omniauth_crowd + +* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet +* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it +* Fork the project +* Start a feature/bugfix branch +* Commit and push until you are happy with your contribution +* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally. +* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it. + +## Copyright + +Copyright (c) 2011-14 Rob Di Marco. See LICENSE.txt for +further details. + diff --git a/vendor/gems/omniauth_crowd/Rakefile b/vendor/gems/omniauth_crowd/Rakefile new file mode 100644 index 00000000000..4786a6c34d1 --- /dev/null +++ b/vendor/gems/omniauth_crowd/Rakefile @@ -0,0 +1,12 @@ +#!/usr/bin/env rake +require "bundler/gem_tasks" +require 'rspec/core/rake_task' + +desc 'Default: run specs.' +task :default => :spec + +desc "Run specs" +RSpec::Core::RakeTask.new + +desc 'Run specs' +task :default => :spec \ No newline at end of file diff --git a/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd.rb b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd.rb new file mode 100755 index 00000000000..7e3829b9b95 --- /dev/null +++ b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd.rb @@ -0,0 +1,97 @@ +require 'omniauth' +require 'active_support' +require 'active_support/core_ext/object' +module OmniAuth + module Strategies + class Crowd + include OmniAuth::Strategy + + autoload :Configuration, 'omniauth/strategies/crowd/configuration' + autoload :CrowdValidator, 'omniauth/strategies/crowd/crowd_validator' + def initialize(app, options = {}, &block) + options.symbolize_keys!() + super(app, {:name=> :crowd}.merge(options), &block) + @configuration = OmniAuth::Strategies::Crowd::Configuration.new(options) + end + + protected + + def request_phase + if env['REQUEST_METHOD'] == 'GET' + + if @configuration.use_sessions? && request.cookies[@configuration.session_cookie] + redirect callback_url + else + get_credentials + end + + elsif (env['REQUEST_METHOD'] == 'POST') && (not request.params['username']) + get_credentials + else + session['omniauth.crowd'] = {'username' => request['username'], 'password' => request['password']} + redirect callback_url + end + end + + def get_client_ip + env['HTTP_X_FORWARDED_FOR'] ? env['HTTP_X_FORWARDED_FOR'] : env['REMOTE_ADDRESS'] + end + + def get_sso_tokens + env['HTTP_COOKIE'].split(';').select { |val| + val.strip.start_with?(@configuration.session_cookie) + }.map { |val| + val.strip.split('=').last + } + end + + def get_credentials + + configuration = @configuration + + OmniAuth::Form.build(:title => (options[:title] || "Crowd Authentication")) do + text_field 'Login', 'username' + password_field 'Password', 'password' + + if configuration.use_sessions? && configuration.sso_url + fieldset 'SSO' do + html "" + (configuration.sso_url_image ? "" : '') + "" + end + end + + end.to_response + + end + + def callback_phase + + creds = session.delete 'omniauth.crowd' + username = creds.nil? ? nil : creds['username'] + password = creds.nil? ? nil : creds['password'] + + unless creds + if @configuration.use_sessions? && request.cookies[@configuration.session_cookie] + validator = CrowdValidator.new(@configuration, username, password, get_client_ip, get_sso_tokens) + else + return fail!(:no_credentials) + end + else + validator = CrowdValidator.new(@configuration, username, password, get_client_ip, nil) + end + + @user_info = validator.user_info + + return fail!(:invalid_credentials) if @user_info.nil? || @user_info.empty? + + super + end + + def auth_hash + OmniAuth::Utils.deep_merge(super, { + 'uid' => @user_info.delete("user"), + 'info' => @user_info + }) + end + end + end +end diff --git a/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/configuration.rb b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/configuration.rb new file mode 100644 index 00000000000..8816651054f --- /dev/null +++ b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/configuration.rb @@ -0,0 +1,110 @@ +require 'rack' + +module OmniAuth + module Strategies + class Crowd + class Configuration + DEFAULT_SESSION_URL = "%s/rest/usermanagement/latest/session" + DEFAULT_AUTHENTICATION_URL = "%s/rest/usermanagement/latest/authentication" + DEFAULT_USER_GROUP_URL = "%s/rest/usermanagement/latest/user/group/direct" + DEFAULT_CONTENT_TYPE = 'application/xml' + DEFAULT_SESSION_COOKIE = 'crowd.token_key' + + attr_reader :crowd_application_name, :crowd_password, :disable_ssl_verification, :include_users_groups, :use_sessions, :session_url, :content_type, :session_cookie, :sso_url, :sso_url_image + + alias :"disable_ssl_verification?" :disable_ssl_verification + alias :"include_users_groups?" :include_users_groups + alias :"use_sessions?" :use_sessions + + # @param [Hash] params configuration options + # @option params [String, nil] :crowd_server_url the Crowd server root URL; probably something like + # `https://crowd.mycompany.com` or `https://crowd.mycompany.com/crowd`; optional. + # @option params [String, nil] :crowd_authentication_url (:crowd_server_url + '/rest/usermanagement/latest/authentication') the URL to which to + # use for authenication; optional if `:crowd_server_url` is specified, + # required otherwise. + # @option params [String, nil] :application_name the application name specified in Crowd for this application, required. + # @option params [String, nil] :application_password the application password specified in Crowd for this application, required. + # @option params [Boolean, nil] :disable_ssl_verification disable verification for SSL cert, + # helpful when you developing with a fake cert. + # @option params [Boolean, true] : include a list of user groups when getting information ont he user + # @option params [String, nil] :crowd_user_group_url (:crowd_server_url + '/rest/usermanagement/latest/user/group/direct') the URL to which to + # use for retrieving users groups optional if `:crowd_server_url` is specified, or if `:include_user_groups` is false + # required otherwise. + # @option params [Boolean, false] :use_sessions Use Crowd sessions. If the user logins with user and password create a new Crowd session. Update the session if only a session token is sent (Cookie name set by option session_cookie) + # @option params [String, 'crowd.token_key'] :session_cookie Session cookie name. Defaults to: 'crowd.token_key' + # @option params [String, nil] :sso_url URL of the external SSO page. If this parameter is defined the login form will have a link which will redirect to the SSO page. The SSO must return to the URL of the page using omniauth_crowd (Path portion '/users/auth/crowd/callback' is appended to the URL) + # @option params [String, nil] :sso_url_image Optional image URL to be used in SSO link in the login form + def initialize(params) + parse_params params + end + + # Build a Crowd authentication URL from +username+. + # + # @param [String] username the username to validate + # + # @return [String] a URL like `https://crowd.myhost.com/crowd/rest/usermanagement/latest/authentication?username=USERNAME` + def authentication_url(username) + append_username @authentication_url, username + end + + def user_group_url(username) + @user_group_url.nil? ? nil : append_username( @user_group_url, username) + end + + private + def parse_params(options) + options= {:include_user_groups => true}.merge(options || {}) + %w(application_name application_password).each do |opt| + raise ArgumentError.new(":#{opt} MUST be provided") if options[opt.to_sym] == "" + end + @crowd_application_name = options[:application_name] + @crowd_password = options[:application_password] + @use_sessions = options[:use_sessions] + @content_type = options[:content_type] || DEFAULT_CONTENT_TYPE + @session_cookie = options[:session_cookie] || DEFAULT_SESSION_COOKIE + @sso_url = options[:sso_url] + @sso_url_image = options[:sso_url_image] + + unless options.include?(:crowd_server_url) || options.include?(:crowd_authentication_url) + raise ArgumentError.new("Either :crowd_server_url or :crowd_authentication_url MUST be provided") + end + + if @use_sessions + @session_url = options[:crowd_session_url] || DEFAULT_SESSION_URL % options[:crowd_server_url] + validate_is_url 'session URL', @session_url + end + @authentication_url = options[:crowd_authentication_url] || DEFAULT_AUTHENTICATION_URL % options[:crowd_server_url] + validate_is_url 'authentication URL', @authentication_url + @disable_ssl_verification = options[:disable_ssl_verification] + @include_users_groups = options[:include_user_groups] + if @include_users_groups + @user_group_url = options[:crowd_user_group_url] || DEFAULT_USER_GROUP_URL % options[:crowd_server_url] + validate_is_url 'user group URL', @user_group_url + end + + end + + IS_NOT_URL_ERROR_MESSAGE = "%s is not a valid URL" + + def validate_is_url(name, possibly_a_url) + url = URI.parse(possibly_a_url) rescue nil + raise ArgumentError.new(IS_NOT_URL_ERROR_MESSAGE % name) unless url.kind_of?(URI::HTTP) + end + + # Adds +service+ as an URL-escaped parameter to +base+. + # + # @param [String] base the base URL + # @param [String] service the service (a.k.a. return-to) URL. + # + # @return [String] the new joined URL. + def append_username(base, username) + result = base.dup + result << (result.include?('?') ? '&' : '?') + result << 'username=' + result << Rack::Utils.escape(username) + end + + end + end + end +end diff --git a/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/crowd_validator.rb b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/crowd_validator.rb new file mode 100755 index 00000000000..319ebf5e013 --- /dev/null +++ b/vendor/gems/omniauth_crowd/lib/omniauth/strategies/crowd/crowd_validator.rb @@ -0,0 +1,186 @@ +require 'nokogiri' +require 'net/http' +require 'net/https' + +module OmniAuth + module Strategies + class Crowd + class CrowdValidator + AUTHENTICATION_REQUEST_BODY = "%s" + def initialize(configuration, username, password, client_ip, tokens) + @configuration, @username, @password, @client_ip, @tokens = configuration, username, password, client_ip, tokens + @authentiction_uri = URI.parse(@configuration.authentication_url(@username)) + @session_uri = URI.parse(@configuration.session_url) if @configuration.use_sessions + end + + def user_info + user_info_hash = retrieve_user_info! + + if user_info_hash && @configuration.include_users_groups? + user_info_hash = add_user_groups!(user_info_hash) + else + user_info_hash + end + + if user_info_hash && @configuration.use_sessions? + user_info_hash = set_session!(user_info_hash) + end + + user_info_hash + end + + private + def set_session!(user_info_hash) + + response = nil + + if user_info_hash["sso_token"] + response = make_session_request(user_info_hash["sso_token"]) + else + response = make_session_request(nil) + end + + if response.kind_of?(Net::HTTPSuccess) && response.body + doc = Nokogiri::XML(response.body) + user_info_hash["sso_token"] = doc.xpath('//token/text()').to_s + else + OmniAuth.logger.send(:warn, "(crowd) [set_session!] response code: #{response.code.to_s}") + OmniAuth.logger.send(:warn, "(crowd) [set_session!] response body: #{response.body}") + end + + user_info_hash + end + + def add_user_groups!(user_info_hash) + response = make_user_group_request(user_info_hash['user']) + unless response.code.to_i != 200 || response.body.nil? || response.body == '' + doc = Nokogiri::XML(response.body) + user_info_hash["groups"] = doc.xpath("//groups/group/@name").map(&:to_s) + end + user_info_hash + end + + def retrieve_user_info! + response = make_authorization_request + + unless response === nil + unless response.code.to_i != 200 || response.body.nil? || response.body == '' + + doc = Nokogiri::XML(response.body) + result = { + "user" => doc.xpath("//user/@name").to_s, + "name" => doc.xpath("//user/display-name/text()").to_s, + "first_name" => doc.xpath("//user/first-name/text()").to_s, + "last_name" => doc.xpath("//user/last-name/text()").to_s, + "email" => doc.xpath("//user/email/text()").to_s + } + + if doc.at_xpath("//token") + result["sso_token"] = doc.xpath("//token/text()").to_s + end + + result + + else + OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] response code: #{response.code.to_s}") + OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] response body: #{response.body}") + nil + end + else + OmniAuth.logger.send(:warn, "(crowd) [retrieve_user_info!] None of the session tokens were valid") + nil + end + end + + def make_request(uri, body=nil) + http_method = body.nil? ? Net::HTTP::Get : Net::HTTP::Post + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = uri.port == 443 || uri.instance_of?(URI::HTTPS) + http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl? && @configuration.disable_ssl_verification? + http.start do |c| + req = http_method.new(uri.query.nil? ? uri.path : "#{uri.path}?#{uri.query}") + req.body = body if body + req.basic_auth @configuration.crowd_application_name, @configuration.crowd_password + if @configuration.content_type + req.add_field 'Content-Type', @configuration.content_type + end + http.request(req) + end + end + + def make_user_group_request(username) + make_request(URI.parse(@configuration.user_group_url(username))) + end + + def make_authorization_request + + if @configuration.use_sessions? && @tokens.kind_of?(Array) + make_session_retrieval_request + else + make_request(@authentiction_uri, make_authentication_request_body(@password)) + end + end + + def make_session_request(token) + + root = url = validation_factor = nil + doc = Nokogiri::XML::Document.new + + if token === nil + + url = @session_uri + root = doc.create_element('authentication-context') + + doc.root = root + root.add_child(doc.create_element('username', @username)) + root.add_child(doc.create_element('password', @password)) + + else + url = URI.parse(@session_uri.to_s() + "/#{token}") + end + + if @configuration.use_sessions? || @client_ip + + if root === nil + root = doc.create_element('validation-factors') + doc.root = root + else + root.add_child(doc.create_element('validation-factors')) + end + + validation_factor = doc.create_element('validation-factor') + validation_factor.add_child(doc.create_element('name', 'remote_address')) + validation_factor.add_child(doc.create_element('value', @client_ip)) + + doc.xpath('//validation-factors').first.add_child(validation_factor) + + end + + make_request(url, doc.to_s) + + end + + # create the body using Nokogiri so proper encoding of passwords can be ensured + def make_authentication_request_body(password) + request_body = Nokogiri::XML(AUTHENTICATION_REQUEST_BODY) + password_value = request_body.at_css "value" + password_value.content = password + return request_body.root.to_s # return the body without the xml header + end + + def make_session_retrieval_request + + response = nil + + @tokens.any? { |token| + response = make_request(URI.parse(@session_uri.to_s() + "/#{token}")) + response.code.to_i == 200 && !response.body.nil? && response.body != '' + } + + response + + end + end + end + end +end diff --git a/vendor/gems/omniauth_crowd/lib/omniauth_crowd.rb b/vendor/gems/omniauth_crowd/lib/omniauth_crowd.rb new file mode 100644 index 00000000000..56cf75c4e36 --- /dev/null +++ b/vendor/gems/omniauth_crowd/lib/omniauth_crowd.rb @@ -0,0 +1 @@ +require 'omniauth/strategies/crowd' \ No newline at end of file diff --git a/vendor/gems/omniauth_crowd/lib/omniauth_crowd/version.rb b/vendor/gems/omniauth_crowd/lib/omniauth_crowd/version.rb new file mode 100644 index 00000000000..378fb1c9e69 --- /dev/null +++ b/vendor/gems/omniauth_crowd/lib/omniauth_crowd/version.rb @@ -0,0 +1,5 @@ +module OmniAuth + module Crowd + VERSION = "2.4.0" + end +end diff --git a/vendor/gems/omniauth_crowd/omniauth_crowd.gemspec b/vendor/gems/omniauth_crowd/omniauth_crowd.gemspec new file mode 100644 index 00000000000..4963c5fef1b --- /dev/null +++ b/vendor/gems/omniauth_crowd/omniauth_crowd.gemspec @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +require File.expand_path('../lib/omniauth_crowd/version', __FILE__) +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) + +Gem::Specification.new do |gem| + gem.authors = ["Robert Di Marco"] + gem.email = ["rob@innovationontherun.com"] + gem.description = "This is an OmniAuth provider for Atlassian Crowd's REST API. It allows you to easily integrate your Rack application in with Atlassian Crowd." + gem.summary = "An OmniAuth provider for Atlassian Crowd REST API" + gem.homepage = "http://github.com/robdimarco/omniauth_crowd" + gem.files = Dir.glob("lib/**/*.*") + gem.test_files = Dir.glob("spec/**/**/*.*") + gem.name = "omniauth_crowd" + gem.require_paths = ["lib"] + gem.version = OmniAuth::Crowd::VERSION + + gem.add_runtime_dependency 'omniauth', '~> 1.0', '< 3' + gem.add_runtime_dependency 'nokogiri', '>= 1.4.4' + gem.add_runtime_dependency 'activesupport', '>= 0' + gem.add_development_dependency(%q, [">= 0"]) + gem.add_development_dependency(%q, [">= 0"]) + gem.add_development_dependency(%q, [">= 0"]) + gem.add_development_dependency(%q, ["~> 3.2.5"]) + gem.add_development_dependency(%q, ["~> 3.0.0"]) + gem.add_development_dependency(%q, ["~> 3.0.0"]) + gem.add_development_dependency(%q, ["> 1.0.0"]) +end diff --git a/vendor/gems/omniauth_crowd/spec/fixtures/groups.xml b/vendor/gems/omniauth_crowd/spec/fixtures/groups.xml new file mode 100644 index 00000000000..dd71a00436d --- /dev/null +++ b/vendor/gems/omniauth_crowd/spec/fixtures/groups.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/vendor/gems/omniauth_crowd/spec/fixtures/session.xml b/vendor/gems/omniauth_crowd/spec/fixtures/session.xml new file mode 100644 index 00000000000..42719d25f3f --- /dev/null +++ b/vendor/gems/omniauth_crowd/spec/fixtures/session.xml @@ -0,0 +1,8 @@ + + + rtk8eMvqq00EiGn5iJCMZQ00 + + + + + \ No newline at end of file diff --git a/vendor/gems/omniauth_crowd/spec/fixtures/success.xml b/vendor/gems/omniauth_crowd/spec/fixtures/success.xml new file mode 100644 index 00000000000..a2324ab6b40 --- /dev/null +++ b/vendor/gems/omniauth_crowd/spec/fixtures/success.xml @@ -0,0 +1,11 @@ + + + + Foo + Foobaz + Foo Foobaz + foo@example.org + + true + + diff --git a/vendor/gems/omniauth_crowd/spec/omniauth/strategies/crowd_spec.rb b/vendor/gems/omniauth_crowd/spec/omniauth/strategies/crowd_spec.rb new file mode 100755 index 00000000000..f234ef82e76 --- /dev/null +++ b/vendor/gems/omniauth_crowd/spec/omniauth/strategies/crowd_spec.rb @@ -0,0 +1,387 @@ +require 'spec_helper' + +describe OmniAuth::Strategies::Crowd, :type=>:strategy do + include OmniAuth::Test::StrategyTestCase + def strategy + @crowd_server_url ||= 'https://crowd.example.org' + @application_name ||= 'bogus_app' + @application_password ||= 'bogus_app_password' + [OmniAuth::Strategies::Crowd, {:crowd_server_url => @crowd_server_url, + :application_name => @application_name, + :application_password => @application_password, + :use_sessions => @using_sessions, + :sso_url => @sso_url, + :sso_url_image => @sso_url_image + }] + end + + @using_sessions = false + @sso_url = nil + @sso_url_image = nil + let(:config) { OmniAuth::Strategies::Crowd::Configuration.new(strategy[1]) } + let(:validator) { OmniAuth::Strategies::Crowd::CrowdValidator.new(config, 'foo', 'bar', nil, nil) } + + describe 'Authentication Request Body' do + + it 'should send password in session request' do + body = <<-BODY.strip + + bar + +BODY + expect(validator.send(:make_authentication_request_body, 'bar')).to eq(body) + end + + it 'should escape special characters username and password in session request' do + body = <<-BODY.strip + + bar< + +BODY + expect(validator.send(:make_authentication_request_body, 'bar<')).to eq(body) + end + end + + describe 'GET /auth/crowd' do + it 'should show the login form' do + get '/auth/crowd' + expect(last_response).to be_ok + end + end + + describe 'POST /auth/crowd' do + it 'should redirect to callback' do + post '/auth/crowd', :username=>'foo', :password=>'bar' + expect(last_response).to be_redirect + expect(last_response.headers['Location']).to eq('http://example.org/auth/crowd/callback') + end + end + + describe 'GET /auth/crowd/callback without any credentials' do + it 'should fail' do + get '/auth/crowd/callback' + expect(last_response).to be_redirect + expect(last_response.headers['Location']).to match(/no_credentials/) + end + end + + describe 'GET /auth/crowd/callback with credentials can be successful' do + context "when using authentication endpoint" do + before do + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/authentication?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'success.xml'))) + + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml'))) + + #Adding this to prevent Content-Type text/xml from being added back in the future + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo").with(:headers => {"Content-Type" => "text/xml"}). + to_return(:status => [415, "Unsupported Media Type"]) + get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}} + end + it 'should call through to the master app' do + expect(last_response.body).to eq('true') + end + it 'should have an auth hash' do + auth = last_request.env['omniauth.auth'] + expect(auth).to be_kind_of(Hash) + end + it 'should have good data' do + auth = last_request.env['omniauth.auth'] + expect(auth['provider']).to eq(:crowd) + expect(auth['uid']).to eq('foo') + expect(auth['info']).to be_kind_of(Hash) + expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort) + end + end + + describe "when using session endpoint" do + before do + @using_sessions = true + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/authentication?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'success.xml'))) + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/session"). + to_return(:status => 201, :body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'session.xml'))) + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml'))) + end + + after { @using_sessions = false } + + it 'should call through to the master app' do + get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}} + expect(last_response.body).to eq('true') + end + + it 'should have an auth hash' do + get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}} + expect(last_request.env['omniauth.auth']).to be_kind_of(Hash) + end + + it 'should have good data' do + get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}} + auth = last_request.env['omniauth.auth'] + expect(auth['provider']).to eq(:crowd) + expect(auth['uid']).to eq('foo') + expect(auth['info']).to be_kind_of(Hash) + expect(auth['info']['sso_token']).to eq('rtk8eMvqq00EiGn5iJCMZQ00') + expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort) + end + end + end + + describe 'GET /auth/crowd/callback with credentials will fail' do + before do + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/authentication?username=foo"). + to_return(:status=>400) + get '/auth/crowd/callback', nil, 'rack.session'=>{'omniauth.crowd'=> {"username"=>"foo", "password"=>"ba"}} + end + it 'should fail' do + expect(last_response).to be_redirect + expect(last_response.headers['Location']).to match(/invalid_credentials/) + end + end + + describe 'GET /auth/crowd without credentials will redirect to login form' do + + sso_url = 'https://foo.bar' + + before do + @using_sessions = true + @sso_url = sso_url + end + + it 'should have the SSO button in the response body' do + + found_legend = found_anchor = nil + + get '/auth/crowd' + + Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element| + + if element.name === 'legend' && element.content() === 'SSO' + found_legend = true + elsif element.name === 'a' && element.attr('href') === "#{sso_url}/users/auth/crowd/callback" + found_anchor = true + end + end + + expect(found_legend).to(be(true)) + expect(found_anchor).to(be(true)) + + end + + after do + @using_sessions = false + @sso_url = nil + end + + end + + describe 'GET /auth/crowd without credentials will redirect to login form which has custom image in the SSO link' do + + sso_url = 'https://foo.bar' + sso_url_image = 'https://foo.bar/image.png' + + before do + @using_sessions = true + @sso_url = sso_url + @sso_url_image = 'https://foo.bar/image.png' + end + + it 'should have the SSO button with a custom image in the response body' do + + found_legend = found_anchor = found_image = false + + get '/auth/crowd' + + Nokogiri::HTML(last_response.body).xpath('//html/body/form/fieldset/*').each do |element| + + if element.name === 'legend' && element.content() === 'SSO' + found_legend = true + elsif element.name === 'a' && element.attr('href') === "#{sso_url}/users/auth/crowd/callback" + + found_anchor = true + + if element.children.length === 1 && element.children.first.name === 'img' && element.children.first.attr('src') === sso_url_image + found_image = true + end + + end + end + + expect(found_legend).to(be(true)) + expect(found_anchor).to(be(true)) + expect(found_image).to(be(true)) + + end + + after do + @using_sessions = false + @sso_url = nil + @sso_url_image = nil + end + + end + + describe 'GET /auth/crowd without credentials but with SSO cookie will redirect to callback' do + + sso_url = 'https://foo.bar' + + before do + + @using_sessions = true + @sso_url = sso_url + + set_cookie('crowd.token_key=foobar') + + end + + it 'should redirect to callback' do + get '/auth/crowd' + expect(last_response).to be_redirect + expect(last_response.headers['Location']).to eq('http://example.org/auth/crowd/callback') + end + + after do + + @using_sessions = false + @sso_url = nil + + clear_cookies() + + end + + end + + describe 'POST /auth/crowd/callback without credentials but with SSO cookie will redirect to login form because session is invalid' do + + sso_url = 'https://foo.bar' + token = 'foobar' + + before do + + @using_sessions = true + @sso_url = sso_url + + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/session/#{token}"). + to_return(:status => [404]) + + set_cookie("crowd.token_key=#{token}") + + end + + it 'should redirect to login form' do + post '/auth/crowd/callback' + expect(last_response).to be_redirect + expect(last_response.headers['Location']).to match(/invalid_credentials/) + end + + after do + + @using_sessions = false + @sso_url = nil + + clear_cookies() + + end + + end + + describe 'GET /auth/crowd/callback without credentials but with SSO cookie will succeed' do + + sso_url = 'https://foo.bar' + token = 'rtk8eMvqq00EiGn5iJCMZQ00' + + before do + + @using_sessions = true + @sso_url = sso_url + + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/session/#{token}"). + to_return(:status => 200, :body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'session.xml'))) + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/session/#{token}"). + to_return(:status => 200) + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml'))) + + set_cookie("crowd.token_key=#{token}") + + end + + it 'should return user data' do + + auth = nil + + get '/auth/crowd/callback' + + auth = last_request.env['omniauth.auth'] + + expect(auth['provider']).to eq(:crowd) + expect(auth['uid']).to eq('foo') + expect(auth['info']).to be_kind_of(Hash) + expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort) + + end + + after do + + @using_sessions = false + @sso_url = nil + + clear_cookies() + + end + + end + + describe 'GET /auth/crowd/callback without credentials but with multiple SSO cookies will succeed because one of them is valid' do + + sso_url = 'https://foo.bar' + + before do + + @using_sessions = true + @sso_url = sso_url + + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/session/foo"). + to_return(:status => 404) + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/session/fubar"). + to_return(:status => 404) + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/session/rtk8eMvqq00EiGn5iJCMZQ00"). + to_return(:status => 200, :body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'session.xml'))) + stub_request(:post, "https://crowd.example.org/rest/usermanagement/latest/session/rtk8eMvqq00EiGn5iJCMZQ00"). + to_return(:status => 200) + stub_request(:get, "https://crowd.example.org/rest/usermanagement/latest/user/group/direct?username=foo"). + to_return(:body => File.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'groups.xml'))) + + header('Cookie', "crowd.token_key=foo;crowd.token_key=rtk8eMvqq00EiGn5iJCMZQ00;crowd.token_key=fubar") + + end + + it 'should return user data' do + + auth = nil + + get '/auth/crowd/callback' + + auth = last_request.env['omniauth.auth'] + + expect(auth['provider']).to eq(:crowd) + expect(auth['uid']).to eq('foo') + expect(auth['info']).to be_kind_of(Hash) + expect(auth['info']['groups'].sort).to eq(["Developers", "jira-users"].sort) + + end + + after do + + @using_sessions = false + @sso_url = nil + + header('Cookie', nil) + + end + + end +end diff --git a/vendor/gems/omniauth_crowd/spec/spec_helper.rb b/vendor/gems/omniauth_crowd/spec/spec_helper.rb new file mode 100644 index 00000000000..13683c95062 --- /dev/null +++ b/vendor/gems/omniauth_crowd/spec/spec_helper.rb @@ -0,0 +1,14 @@ +require 'bundler/setup' +Bundler.setup +require 'rack/test' +require 'webmock' +require 'webmock/rspec' +require 'nokogiri' + +require 'omniauth_crowd' +RSpec.configure do |config| + WebMock.disable_net_connect! + config.include Rack::Test::Methods + config.raise_errors_for_deprecations! +end +