├── .gitignore ├── Gemfile ├── Gemfile.lock ├── License ├── README.md ├── app ├── controllers │ └── redmine_oauth_controller.rb ├── helpers │ └── redmine_omniauth_helper.rb └── views │ ├── hooks │ └── _view_account_login_bottom.html.erb │ └── settings │ └── _gitlab_settings.html.erb ├── assets ├── images │ └── gitlab_login_icon.png └── stylesheets │ └── buttons.css ├── config ├── locales │ ├── en.yml │ └── ru.yml └── routes.rb ├── init.rb └── lib ├── helpers ├── checker.rb └── mail_helper.rb └── redmine_omniauth_gitlab └── hooks.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'oauth2' 4 | gem "json", ">= 1.7.7" 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | faraday (0.15.4) 5 | multipart-post (>= 1.2, < 3) 6 | json (2.1.0) 7 | jwt (2.1.0) 8 | multi_json (1.13.1) 9 | multi_xml (0.6.0) 10 | multipart-post (2.0.0) 11 | oauth2 (1.4.1) 12 | faraday (>= 0.8, < 0.16.0) 13 | jwt (>= 1.0, < 3.0) 14 | multi_json (~> 1.3) 15 | multi_xml (~> 0.5) 16 | rack (>= 1.2, < 3) 17 | rack (2.0.6) 18 | 19 | PLATFORMS 20 | ruby 21 | 22 | DEPENDENCIES 23 | json (>= 1.7.7) 24 | oauth2 25 | 26 | BUNDLED WITH 27 | 1.15.1 28 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 ziteng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Redmine omniauth gitlab 2 | 3 | This plugin is used to authenticate Redmine users using gitlab's OAuth2 provider. 4 | 5 | The major logic as similar as [redmine_omniauth_google](https://github.com/twinslash/redmine_omniauth_google) 6 | 7 | ### Installation: 8 | 9 | Download the plugin and install required gems: 10 | 11 | ```console 12 | cd /path/to/redmine/plugins 13 | git clone https://github.com/applewu/redmine_omniauth_gitlab 14 | cd /path/to/redmine 15 | bundle install 16 | ``` 17 | 18 | Restart the redmine 19 | ```console 20 | /path/to/redmine/ctlscript.sh restart 21 | ``` 22 | 23 | ### Registration 24 | 25 | To authenticate via gitlab you must first register your redmine instance via your gitlab 26 | 27 | ### Configuration 28 | 29 | * Login as a user with administrative privileges. 30 | * In top menu select "Administration". 31 | * Click "Plugins" 32 | * In plugins list, click "Configure" in the row for "Redmine Omniauth gitlab plugin" 33 | * Enter the Сlient ID & Client Secret shown when you registered your application via gitlab Cloud Console. 34 | * Check the box near "Oauth authentication" 35 | * Click Apply. 36 | 37 | Users can now to use their gitlab Account to log in to your instance of Redmine. 38 | 39 | Additionaly 40 | * Setup value Autologin in Settings on tab Authentification 41 | 42 | ### Other options 43 | 44 | By default, all user email domains are allowed to authenticate through gitlab. 45 | If you want to limit the user email domains allowed to use the plugin, list one per line in the "Allowed domains" text box. 46 | 47 | For example: 48 | 49 | ```text 50 | onedomain.com 51 | otherdomain.com 52 | ``` 53 | 54 | With the above configuration, only users with email addresses on the domains "onedomain.com" and "otherdomain.com" will be allowed to acccess your Redmine instance using gitlab OAuth. 55 | 56 | ### Authentication Workflow 57 | 58 | 1. An unauthenticated user requests the URL to your Redmine instance. 59 | 2. User clicks the "Login via gitlab" buton. 60 | 3. The plugin redirects them to a gitlab sign in page if they are not already signed in to their gitlab account. 61 | 4. gitlab redirects user back to Redmine, where the gitlab OAuth plugin's controller takes over. 62 | 63 | One of the following cases will occur: 64 | 1. If self-registration is enabled (Under Administration > Settings > Authentication), user is redirected to 'my/page' 65 | 2. Otherwse, the an account is created for the user (referencing their gitlab OAuth2 ID). A Redmine administrator must activate the account for it to work. 66 | -------------------------------------------------------------------------------- /app/controllers/redmine_oauth_controller.rb: -------------------------------------------------------------------------------- 1 | require 'account_controller' 2 | require 'json' 3 | 4 | class RedmineOauthController < AccountController 5 | include Helpers::MailHelper 6 | include Helpers::Checker 7 | 8 | def oauth_gitlab 9 | if Setting.plugin_redmine_omniauth_gitlab[:oauth_authentification] 10 | session[:back_url] = params[:back_url] 11 | redirect_to oauth_client.auth_code.authorize_url(:redirect_uri => oauth_gitlab_callback_url) 12 | else 13 | password_authentication 14 | end 15 | end 16 | 17 | def oauth_gitlab_callback 18 | if params[:error] 19 | flash[:error] = l(:notice_access_denied) 20 | redirect_to signin_path 21 | else 22 | token = oauth_client.auth_code.get_token(params[:code], :redirect_uri => oauth_gitlab_callback_url) 23 | result = token.get( settings[:site]+'/api/v3/user') 24 | info = JSON.parse(result.body) 25 | puts(info) 26 | puts("email : " + info["email"]) 27 | if info && info["email"] 28 | if allowed_domain_for?(info["email"]) 29 | try_to_login info 30 | else 31 | flash[:error] = l(:notice_domain_not_allowed, :domain => parse_email(info["email"])[:domain]) 32 | redirect_to signin_path 33 | end 34 | else 35 | flash[:error] = l(:notice_unable_to_obtain_gitlab_credentials) 36 | redirect_to signin_path 37 | end 38 | end 39 | end 40 | 41 | def try_to_login info 42 | params[:back_url] = session[:back_url] 43 | session.delete(:back_url) 44 | user = User.joins(:email_addresses).where(:email_addresses => {:address => info["email"]}).first_or_create 45 | if user.new_record? 46 | # Self-registration off 47 | redirect_to(home_url) && return unless Setting.self_registration? 48 | # Create on the fly 49 | user.firstname, user.lastname = info["name"].split(' ') unless info['name'].nil? 50 | user.firstname ||= info[:given_name] 51 | user.lastname ||= info[:family_name] 52 | user.mail = info["email"] 53 | user.login = info["username"] 54 | user.random_password 55 | user.register 56 | 57 | case Setting.self_registration 58 | when '1' 59 | register_by_email_activation(user) do 60 | onthefly_creation_failed(user) 61 | end 62 | when '3' 63 | register_automatically(user) do 64 | onthefly_creation_failed(user) 65 | end 66 | else 67 | register_manually_by_administrator(user) do 68 | onthefly_creation_failed(user) 69 | end 70 | end 71 | else 72 | # Existing record 73 | if user.active? 74 | successful_authentication(user) 75 | else 76 | # Redmine 2.4 adds an argument to account_pending 77 | if Redmine::VERSION::MAJOR > 2 or 78 | (Redmine::VERSION::MAJOR == 2 and Redmine::VERSION::MINOR >= 4) 79 | account_pending(user) 80 | else 81 | account_pending 82 | end 83 | end 84 | end 85 | end 86 | 87 | def oauth_client 88 | @client ||= OAuth2::Client.new(settings[:client_id], settings[:client_secret], 89 | :token_method => :post, 90 | :site => settings[:site], 91 | :authorize_url => settings[:site] + '/oauth/authorize', 92 | :token_url => settings[:site] + '/oauth/token' 93 | ) 94 | end 95 | 96 | def settings 97 | @settings ||= Setting.plugin_redmine_omniauth_gitlab 98 | end 99 | 100 | end 101 | -------------------------------------------------------------------------------- /app/helpers/redmine_omniauth_helper.rb: -------------------------------------------------------------------------------- 1 | module RedmineOmniauthHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/views/hooks/_view_account_login_bottom.html.erb: -------------------------------------------------------------------------------- 1 | <%= stylesheet_link_tag 'buttons', :plugin => 'redmine_omniauth_gitlab' %> 2 | 3 | <% if Setting.plugin_redmine_omniauth_gitlab[:oauth_authentification] %> 4 | <%= link_to oauth_gitlab_path(:back_url => back_url) do %> 5 | <%= button_tag :class => 'button-login' do %> 6 | <%= image_tag('/plugin_assets/redmine_omniauth_gitlab/images/gitlab_login_icon.png', :class => 'button-login-icon', :alt => l(:login_via_gitlab)) %> 7 | <%= content_tag :div, l(:login_via_gitlab), :class => 'button-login-text' %> 8 | <% end %> 9 | <% end %> 10 | <% end %> 11 | -------------------------------------------------------------------------------- /app/views/settings/_gitlab_settings.html.erb: -------------------------------------------------------------------------------- 1 |

2 | 3 | <%= text_field_tag 'settings[site]', @settings[:site] %> 4 |

5 |

6 | 7 | <%= text_field_tag 'settings[client_id]', @settings[:client_id] %> 8 |

9 |

10 | 11 | <%= text_field_tag 'settings[client_secret]', @settings[:client_secret] %> 12 |

13 |

14 | 15 | <%= text_area_tag "settings[allowed_domains]", @settings[:allowed_domains], :rows => 5 %> 16 |

17 |

18 | 19 | <%= check_box_tag "settings[oauth_authentification]", true, @settings[:oauth_authentification] %> 20 |

21 | -------------------------------------------------------------------------------- /assets/images/gitlab_login_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/applewu/redmine_omniauth_gitlab/b0f48e2aa8a67f461e8c9b058f1a801b56dc6ef0/assets/images/gitlab_login_icon.png -------------------------------------------------------------------------------- /assets/stylesheets/buttons.css: -------------------------------------------------------------------------------- 1 | .button-login { 2 | position: relative; 3 | left: 45%; 4 | display: inline-block; 5 | border: 1px solid #999; 6 | border-radius: 2px; 7 | margin-top: 10px; 8 | width: 135px; 9 | height: 25px; 10 | padding: 0; 11 | } 12 | 13 | .button-login-icon { 14 | float: left; 15 | height: 18px; 16 | padding: 1px 0px 0px 4px; 17 | } 18 | 19 | .button-login-text { 20 | line-height: 21px; 21 | background-image: -webkit-linear-gradient(bottom, #ddd, white); 22 | font-size: 12px; 23 | } 24 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | notice_unable_to_obtain_gitlab_credentials: "Unable to obtain credentials from gitlab." 3 | notice_domain_not_allowed: "You can not login using %{domain} domain." 4 | notice_access_denied: "You must allow to use you gitlab credentials to enter this site." 5 | login_via_gitlab: "Login via gitlab" 6 | -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | notice_unable_to_obtain_gitlab_credentials: "Не удалось получить данные от gitlab." 3 | notice_domain_not_allowed: "Вы не можете войти в систему при помощи домена %{domain}." 4 | notice_access_denied: "Для корректного входа необходимо разрешить приложению доступ к аккаунту." 5 | login_via_gitlab: "Войти с gitlab" 6 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | get 'oauth_gitlab', :to => 'redmine_oauth#oauth_gitlab' 2 | get 'oauth2callback', :to => 'redmine_oauth#oauth_gitlab_callback', :as => 'oauth_gitlab_callback' 3 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'redmine' 2 | 3 | Redmine::Plugin.register :redmine_omniauth_gitlab do 4 | name 'Redmine Omniauth gitlab plugin' 5 | author 'wuziteng2006@163.com' 6 | description 'This is a plugin for Redmine registration through gitlab' 7 | version '0.0.1' 8 | url 'https://github.com/applewu/redmine_omniauth_gitlab' 9 | author_url 'http://appletest.lofter.com/' 10 | 11 | settings :default => { 12 | :site => "", 13 | :client_id => "", 14 | :client_secret => "", 15 | :oauth_autentification => false, 16 | :allowed_domains => "" 17 | }, :partial => 'settings/gitlab_settings' 18 | end 19 | -------------------------------------------------------------------------------- /lib/helpers/checker.rb: -------------------------------------------------------------------------------- 1 | module Helpers 2 | module Checker 3 | def allowed_domain_for? email 4 | allowed_domains = Setting.plugin_redmine_omniauth_gitlab[:allowed_domains] 5 | return unless allowed_domains 6 | allowed_domains = allowed_domains.split 7 | return true if allowed_domains.empty? 8 | allowed_domains.index(parse_email(email)[:domain]) 9 | end 10 | end 11 | end -------------------------------------------------------------------------------- /lib/helpers/mail_helper.rb: -------------------------------------------------------------------------------- 1 | module Helpers 2 | module MailHelper 3 | def parse_email email 4 | email_data = email && email.is_a?(String) ? email.match(/(.*?)@(.*)/) : nil 5 | {:login => email_data[1], :domain => email_data[2]} if email_data 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/redmine_omniauth_gitlab/hooks.rb: -------------------------------------------------------------------------------- 1 | module RedmineOmniauthGitlab 2 | class Hooks < Redmine::Hook::ViewListener 3 | def view_account_login_bottom(context = {}) 4 | context[:controller].send(:render_to_string, { 5 | :partial => "hooks/view_account_login_bottom", 6 | :locals => context}) 7 | end 8 | end 9 | end 10 | --------------------------------------------------------------------------------