omniauth_crowd-2.4.0/0000755000004100000410000000000013341256217014573 5ustar www-datawww-dataomniauth_crowd-2.4.0/Gemfile.lock0000644000004100000410000000270213341256217017016 0ustar www-datawww-dataPATH remote: . specs: omniauth_crowd (2.4.0) activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) 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) 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 rspec (~> 3.0.0) webmock (~> 3.0.0) BUNDLED WITH 1.15.4 omniauth_crowd-2.4.0/.travis.yml0000644000004100000410000000017213341256217016704 0ustar www-datawww-datalanguage: ruby before_install: - gem install bundler -v '~> 1.11' rvm: - "2.0.0" - "2.1.2" - "2.2.4" - "2.3.0" omniauth_crowd-2.4.0/README.md0000644000004100000410000000362513341256217016060 0ustar www-datawww-data# omniauth_crowd 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. omniauth_crowd-2.4.0/spec/0000755000004100000410000000000013341256217015525 5ustar www-datawww-dataomniauth_crowd-2.4.0/spec/fixtures/0000755000004100000410000000000013341256217017376 5ustar www-datawww-dataomniauth_crowd-2.4.0/spec/fixtures/session.xml0000644000004100000410000000060313341256217021602 0ustar www-datawww-data rtk8eMvqq00EiGn5iJCMZQ00 omniauth_crowd-2.4.0/spec/fixtures/groups.xml0000644000004100000410000000050113341256217021433 0ustar www-datawww-data omniauth_crowd-2.4.0/spec/fixtures/success.xml0000644000004100000410000000117113341256217021570 0ustar www-datawww-data Foo Foobaz Foo Foobaz foo@example.org true omniauth_crowd-2.4.0/spec/omniauth/0000755000004100000410000000000013341256217017351 5ustar www-datawww-dataomniauth_crowd-2.4.0/spec/omniauth/strategies/0000755000004100000410000000000013341256217021523 5ustar www-datawww-dataomniauth_crowd-2.4.0/spec/omniauth/strategies/crowd_spec.rb0000755000004100000410000003065113341256217024210 0ustar www-datawww-datarequire '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 omniauth_crowd-2.4.0/spec/spec_helper.rb0000644000004100000410000000043613341256217020346 0ustar www-datawww-datarequire '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 omniauth_crowd-2.4.0/.gitignore0000644000004100000410000000142413341256217016564 0ustar www-datawww-data.ruby-version .ruby-gemset # rcov generated coverage # rdoc generated rdoc # yard generated doc .yardoc # bundler .bundle # jeweler generated pkg # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: # # * Create a file at ~/.gitignore # * Include files you want ignored # * Run: git config --global core.excludesfile ~/.gitignore # # After doing this, these files will be ignored in all your git projects, # saving you from having to 'pollute' every project you touch with them # # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) # # For MacOS: # #.DS_Store # # For TextMate #*.tmproj #tmtags # # For emacs: #*~ #\#* #.\#* # # For vim: #*.swp omniauth_crowd-2.4.0/.document0000644000004100000410000000006713341256217016415 0ustar www-datawww-datalib/**/*.rb bin/* - features/**/*.feature LICENSE.txt omniauth_crowd-2.4.0/omniauth_crowd.gemspec0000644000004100000410000000257313341256217021171 0ustar www-datawww-data# -*- 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.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } gem.files = `git ls-files`.split("\n") gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") gem.name = "omniauth_crowd" gem.require_paths = ["lib"] gem.version = OmniAuth::Crowd::VERSION gem.add_runtime_dependency 'omniauth', '~> 1.0' 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.0.0"]) gem.add_development_dependency(%q, ["~> 3.0.0"]) gem.add_development_dependency(%q, ["> 1.0.0"]) end omniauth_crowd-2.4.0/Rakefile0000644000004100000410000000032613341256217016241 0ustar www-datawww-data#!/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 => :specomniauth_crowd-2.4.0/lib/0000755000004100000410000000000013341256217015341 5ustar www-datawww-dataomniauth_crowd-2.4.0/lib/omniauth_crowd/0000755000004100000410000000000013341256217020363 5ustar www-datawww-dataomniauth_crowd-2.4.0/lib/omniauth_crowd/version.rb0000644000004100000410000000007713341256217022401 0ustar www-datawww-datamodule OmniAuth module Crowd VERSION = "2.4.0" end end omniauth_crowd-2.4.0/lib/omniauth_crowd.rb0000644000004100000410000000004313341256217020705 0ustar www-datawww-datarequire 'omniauth/strategies/crowd'omniauth_crowd-2.4.0/lib/omniauth/0000755000004100000410000000000013341256217017165 5ustar www-datawww-dataomniauth_crowd-2.4.0/lib/omniauth/strategies/0000755000004100000410000000000013341256217021337 5ustar www-datawww-dataomniauth_crowd-2.4.0/lib/omniauth/strategies/crowd/0000755000004100000410000000000013341256217022455 5ustar www-datawww-dataomniauth_crowd-2.4.0/lib/omniauth/strategies/crowd/crowd_validator.rb0000755000004100000410000001474513341256217026203 0ustar www-datawww-datarequire '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 omniauth_crowd-2.4.0/lib/omniauth/strategies/crowd/configuration.rb0000644000004100000410000001377713341256217025670 0ustar www-datawww-datarequire '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 omniauth_crowd-2.4.0/lib/omniauth/strategies/crowd.rb0000755000004100000410000000570213341256217023011 0ustar www-datawww-datarequire '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 omniauth_crowd-2.4.0/Gemfile0000644000004100000410000000014313341256217016064 0ustar www-datawww-datasource 'http://rubygems.org' # Specify your gem's dependencies in omniauth-github.gemspec gemspec omniauth_crowd-2.4.0/LICENSE.txt0000644000004100000410000000204013341256217016412 0ustar www-datawww-dataCopyright (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.