diff --git a/Gemfile.lock b/Gemfile.lock index f2fae008e59..b5e911b63ba 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,6 +89,12 @@ PATH openproject-auth_plugins (8.2.1) omniauth (~> 1.0) +PATH + remote: modules/auth_saml + specs: + openproject-auth_saml (8.2.1) + omniauth-saml (~> 1.10.1) + PATH remote: modules/avatars specs: @@ -543,9 +549,9 @@ GEM nokogiri (~> 1.8, >= 1.8.4) oj (3.7.8) okcomputer (1.17.3) - omniauth-saml (1.7.0) - omniauth (~> 1.3) - ruby-saml (~> 1.4) + omniauth-saml (1.10.1) + omniauth (~> 1.3, >= 1.3.2) + ruby-saml (~> 1.7) openid_connect (1.1.6) activemodel attr_required (>= 1.0.0) @@ -914,8 +920,9 @@ DEPENDENCIES omniauth! omniauth-openid-connect! omniauth-openid_connect-providers! - omniauth-saml (~> 1.7.0) + omniauth-saml (~> 1.10.1) openproject-auth_plugins! + openproject-auth_saml! openproject-avatars! openproject-backlogs! openproject-costs! diff --git a/Gemfile.modules b/Gemfile.modules index b0f5cfba29a..acc6074b2a0 100644 --- a/Gemfile.modules +++ b/Gemfile.modules @@ -2,7 +2,7 @@ # Defines OpenProject (CE) modules and their dependencies # the dependencies from the gemspec from a git repo are ignored # see also https://github.com/bundler/bundler/issues/1041 -gem 'omniauth-saml', '~> 1.7.0' +gem 'omniauth-saml', '~> 1.10.1' gem 'omniauth-openid_connect-providers', git: 'https://github.com/finnlabs/omniauth-openid_connect-providers.git', @@ -15,6 +15,7 @@ gem 'omniauth-openid-connect', group :opf_plugins do gem 'openproject-global_roles', path: 'modules/global_roles' gem 'openproject-auth_plugins', path: 'modules/auth_plugins' + gem 'openproject-auth_saml', path: 'modules/auth_saml' gem 'openproject-openid_connect', path: 'modules/openid_connect' gem 'openproject-documents', path: 'modules/documents' gem 'openproject-my_project_page', path: 'modules/my_project_page' diff --git a/modules/auth_saml/README.md b/modules/auth_saml/README.md new file mode 100644 index 00000000000..ba0287df6e3 --- /dev/null +++ b/modules/auth_saml/README.md @@ -0,0 +1,64 @@ +# OpenProject OmniAuth SAML Single-Sign On + +![](https://github.com/finnlabs/openproject-auth_saml/blob/dev/app/assets/images/auth_provider-saml.png) + +This plugin provides the [OmniAuth SAML strategy](https://github.com/omniauth/omniauth-saml) into OpenProject. + +## Installation + +Add the following entries to your `Gemfile.plugins` in your OpenProject root directory: + + gem 'openproject-auth_plugins', git: 'https://github.com/finnlabs/openproject-auth_plugins', branch: 'stable' + gem "openproject-auth_saml", git: 'https://github.com/finnlabs/openproject-auth_saml', branch: 'stable' + +## Requirements + +* [omniauth-saml gem](https://github.com/omniauth/omniauth-saml) >= 1.4.0 +* [OpenProject](https://www.openproject.org) >= 5.0 +* [openproject-auth_plugins](https://github.com/opf/openproject-auth_plugins) + +## Configuration + +To add your own SAML strategy provider(s), create the following settings file (relative to your OpenProject root): + + config/plugins/auth_saml/settings.yml + +with the following contents: + + your-provider-name: + name: "your-provider-name" + display_name: "My SAML provider" + # Use the default SAML icon + icon: "auth_provider-saml.png" + # omniauth-saml config + assertion_consumer_service_url: "consumer_service_url" + issuer: "issuer" + idp_sso_target_url: "idp_sso_target_url" + idp_cert_fingerprint: "E7:91:B2:E1:..." + attribute_statements: + email: ['mailPrimaryAddress'] + name: ['gecos'] + first_name: ['givenName'] + last_name: ['sn'] + admin: ['openproject-isadmin'] + +The plugin simply passes all options to omniauth-saml. See [their configuration +documentation](https://github.com/omniauth/omniauth-saml#usage) for further +details. + +### Custom Provider Icon + +To add a custom icon to be rendered as your omniauth provider icon, add an +image asset to OpenProject and reference it in your `settings.yml`: + + icon: "my/asset/path/to/icon.png" + +## Copyrights & License + +OpenProject SAML Auth is completely free and open source and released under the +[MIT +License](https://github.com/finnlabs/openproject-auth_saml/blob/dev/LICENSE). + +Copyright (c) 2016 OpenProject GmbH + +The default provider icon is a combination of icons from [Font Awesome by Dave Gandy](http://fontawesome.io). diff --git a/modules/auth_saml/app/assets/images/auth_provider-saml.png b/modules/auth_saml/app/assets/images/auth_provider-saml.png new file mode 100644 index 00000000000..97158c63565 Binary files /dev/null and b/modules/auth_saml/app/assets/images/auth_provider-saml.png differ diff --git a/modules/auth_saml/lib/open_project/auth_saml.rb b/modules/auth_saml/lib/open_project/auth_saml.rb new file mode 100644 index 00000000000..acff9141c17 --- /dev/null +++ b/modules/auth_saml/lib/open_project/auth_saml.rb @@ -0,0 +1,5 @@ +module OpenProject + module AuthSaml + require 'open_project/auth_saml/engine' + end +end diff --git a/modules/auth_saml/lib/open_project/auth_saml/engine.rb b/modules/auth_saml/lib/open_project/auth_saml/engine.rb new file mode 100644 index 00000000000..764fd994b70 --- /dev/null +++ b/modules/auth_saml/lib/open_project/auth_saml/engine.rb @@ -0,0 +1,48 @@ +require 'omniauth-saml' +module OpenProject + module AuthSaml + class Engine < ::Rails::Engine + engine_name :openproject_auth_saml + + include OpenProject::Plugins::ActsAsOpEngine + extend OpenProject::Plugins::AuthPlugin + + register 'openproject-auth_saml', + author_url: 'https://github.com/finnlabs/openproject-auth_saml', + requires_openproject: '>= 5.0.0' + + assets %w( + auth_saml/** + auth_provider-saml.png + ) + + config.after_initialize do + # Automatically update the openproject user whenever their info change in the upstream identity provider + OpenProject::OmniAuth::Authorization.after_login do |user, auth_hash, context| + # see https://github.com/opf/openproject/blob/caa07c5dd470f82e1a76d2bd72d3d55b9d2b0b83/app/controllers/concerns/omniauth_login.rb#L148 + user.update_attributes context.send(:omniauth_hash_to_user_attributes, auth_hash) + end + end + + register_auth_providers do + settings = Rails.root.join('config', 'plugins', 'auth_saml', 'settings.yml') + if settings.exist? + providers = YAML::load(File.open(settings)).symbolize_keys + strategy :saml do + providers.values.map do |h| + h[:openproject_attribute_map] = Proc.new do |auth| + { + login: auth[:uid], + admin: (auth.info['admin'].to_s.downcase == "true") + } + end + h.symbolize_keys + end + end + else + Rails.logger.warn("[auth_saml] Missing settings from '#{settings}', skipping omniauth registration.") + end + end + end + end +end diff --git a/modules/auth_saml/lib/open_project/auth_saml/version.rb b/modules/auth_saml/lib/open_project/auth_saml/version.rb new file mode 100644 index 00000000000..86c0f40a73a --- /dev/null +++ b/modules/auth_saml/lib/open_project/auth_saml/version.rb @@ -0,0 +1,5 @@ +module OpenProject + module AuthSaml + VERSION = ::OpenProject::VERSION.to_semver + end +end diff --git a/modules/auth_saml/lib/openproject-auth_saml.rb b/modules/auth_saml/lib/openproject-auth_saml.rb new file mode 100644 index 00000000000..5c30b502dc4 --- /dev/null +++ b/modules/auth_saml/lib/openproject-auth_saml.rb @@ -0,0 +1 @@ +require 'open_project/auth_saml' diff --git a/modules/auth_saml/openproject-auth_saml.gemspec b/modules/auth_saml/openproject-auth_saml.gemspec new file mode 100644 index 00000000000..8fb3a6e4627 --- /dev/null +++ b/modules/auth_saml/openproject-auth_saml.gemspec @@ -0,0 +1,20 @@ +# encoding: UTF-8 +$:.push File.expand_path("../lib", __FILE__) +$:.push File.expand_path("../../lib", __dir__) + +require 'open_project/auth_saml/version' +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = 'openproject-auth_saml' + s.version = OpenProject::AuthSaml::VERSION + s.authors = 'Cyril Rohr' + s.email = 'cyril.rohr@gmail.com' + s.homepage = 'https://github.com/finnlabs/openproject-auth_saml' + s.summary = 'OmniAuth SAML / Single-Sign On' + s.description = 'Adds the OmniAuth SAML provider to OpenProject' + s.license = 'MIT' + + s.files = Dir['{app,lib}/**/*'] + %w(README.md) + + s.add_dependency 'omniauth-saml', '~> 1.10.1' +end