Skip to content

Commit

Permalink
Merge pull request #25 from vladimirdulov/custom-oidc-provider
Browse files Browse the repository at this point in the history
Custom OIDC provider
  • Loading branch information
picman authored Feb 23, 2024
2 parents 143b426 + 0b744bb commit e7a55de
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 9 deletions.
27 changes: 27 additions & 0 deletions app/controllers/redmine_oauth_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ def oauth
state: oauth_csrf_token,
scope: 'openid profile email'
)
when 'Custom'
redirect_to oauth_client.auth_code.authorize_url(
redirect_uri: oauth_callback_url,
state: oauth_csrf_token,
scope: Setting.plugin_redmine_oauth[:custom_scope]
)
else
flash['error'] = l(:oauth_invalid_provider)
redirect_to signin_path
Expand Down Expand Up @@ -106,6 +112,19 @@ def oauth_callback
user_info = JSON.parse(userinfo_response.body)
user_info['login'] = user_info['preferred_username']
email = user_info['email']
when 'Custom'
token = oauth_client.auth_code.get_token(params['code'], redirect_uri: oauth_callback_url)
if Setting.plugin_redmine_oauth[:custom_profile_endpoint].strip.empty?
user_info = JWT.decode(token.token, nil, false).first
else
userinfo_response = token.get(
Setting.plugin_redmine_oauth[:custom_profile_endpoint],
headers: { 'Accept' => 'application/json' }
)
user_info = JSON.parse(userinfo_response.body)
end
user_info['login'] = user_info[Setting.plugin_redmine_oauth[:custom_uid_field]]
email = user_info[Setting.plugin_redmine_oauth[:custom_email_field]]
else
raise StandardError, l(:oauth_invalid_provider)
end
Expand Down Expand Up @@ -218,6 +237,14 @@ def oauth_client
authorize_url: "/oauth2/#{Setting.plugin_redmine_oauth[:tenant_id]}/v1/authorize",
token_url: "/oauth2/#{Setting.plugin_redmine_oauth[:tenant_id]}/v1/token"
)
when 'Custom'
OAuth2::Client.new(
Setting.plugin_redmine_oauth[:client_id],
Setting.plugin_redmine_oauth[:client_secret],
site: site,
authorize_url: Setting.plugin_redmine_oauth[:custom_auth_endpoint],
token_url: Setting.plugin_redmine_oauth[:custom_token_endpoint]
)
else
raise StandardError, l(:oauth_invalid_provider)
end
Expand Down
2 changes: 1 addition & 1 deletion app/views/hooks/_view_account_login_bottom.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<%= button_tag(name: 'login-oauth', tabindex: 6, id: 'login-oauth-submit', title: l(:oauth_login_with),
style: "background: #{Setting.plugin_redmine_oauth[:button_color]}") do %>
<i id="button_icon" class="<%= Setting.plugin_redmine_oauth[:button_icon] %>"></i>
<%= l(:oauth_login_via, oauth: Setting.plugin_redmine_oauth[:oauth_name]).html_safe %>
<%= l(:oauth_login_via, oauth: Setting.plugin_redmine_oauth[:custom_name].strip.empty? ? Setting.plugin_redmine_oauth[:oauth_name] : Setting.plugin_redmine_oauth[:custom_name]).html_safe %>
<% end %>
<% end %>
<% end %>
Expand Down
53 changes: 50 additions & 3 deletions app/views/settings/_oauth_settings.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
%w(Google Google),
%w(Keycloak Keycloak),
%w(Okta Okta),
%w(Custom),
["&nbsp;".html_safe, 'none']
], @settings[:oauth_name]), onchange: 'oauth_settings_visibility()' %>
<em class="info"><%= l(:oauth_provider_info) %></em>
Expand All @@ -56,12 +57,16 @@
<%= button_tag(name: 'login-oauth', id: 'login-oauth-button', title: l(:oauth_login_with), style: style,
disabled: true) do %>
<i id="button_icon" class="<%= @settings[:button_icon] %>"></i>
<%= l(:oauth_login_via, oauth: @settings[:oauth_name]).html_safe %>
<%= l(:oauth_login_via, oauth: !@settings[:custom_name].nil? && !@settings[:custom_name].empty? ? @settings[:custom_name] : @settings[:oauth_name]).html_safe %>
<% end %>
</span>
<em class="info"><%= l(:oauth_button_info) %></em>
</p>
<p>
<% if %w(Custom).include?(@settings[:oauth_name]) %>
<p id="oauth_options_site" style="display: none">
<% else %>
<p id="oauth_options_site">
<% end %>
<label><%= l(:oauth_site) %></label>
<%= text_field_tag 'settings[site]', @settings[:site], size: 40 %>
<em class="info"><%= l(:oauth_site_info) %></em>
Expand All @@ -76,7 +81,7 @@
<%= text_field_tag 'settings[client_secret]', @settings[:client_secret], size: 40 %>
<em class="info"><%= l(:oauth_client_secret_info) %></em>
</p>
<% if %w(GitLab Google).include?(@settings[:oauth_name]) %>
<% if %w(GitLab Google Custom).include?(@settings[:oauth_name]) %>
<p id="oauth_options_tenant" style="display: none">
<% else %>
<p id="oauth_options_tenant">
Expand All @@ -85,4 +90,46 @@
<%= text_field_tag 'settings[tenant_id]', @settings[:tenant_id], size: 40 %>
<em class="info"><%= l(:oauth_tenant_id_info) %></em>
</p>
<% if %w(Custom).include?(@settings[:oauth_name]) %>
<div id="oauth_options_custom">
<% else %>
<div id="oauth_options_custom" style="display: none">
<% end %>
<p>
<label><%= l(:oauth_custom_name) %></label>
<input type="text" id="settings_custom_name" name="settings[custom_name]" value="<%= @settings[:custom_name] %>"
onChange="oauth_set_btn_title();">
<em class="info"><%= l(:oauth_custom_name_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_auth_endpoint) %></label>
<%= text_field_tag 'settings[custom_auth_endpoint]', @settings[:custom_auth_endpoint], size: 80 %>
<em class="info"><%= l(:oauth_custom_auth_endpoint_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_token_endpoint) %></label>
<%= text_field_tag 'settings[custom_token_endpoint]', @settings[:custom_token_endpoint], size: 80 %>
<em class="info"><%= l(:oauth_custom_token_endpoint_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_profile_endpoint) %></label>
<%= text_field_tag 'settings[custom_profile_endpoint]', @settings[:custom_profile_endpoint], size: 80 %>
<em class="info"><%= l(:oauth_custom_profile_endpoint_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_scope) %></label>
<%= text_field_tag 'settings[custom_scope]', @settings[:custom_scope], size: 40 %>
<em class="info"><%= l(:oauth_custom_scope_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_uid_field) %></label>
<%= text_field_tag 'settings[custom_uid_field]', @settings[:custom_uid_field], size: 40 %>
<em class="info"><%= l(:oauth_custom_uid_field_info) %></em>
</p>
<p>
<label><%= l(:oauth_custom_email_field) %></label>
<%= text_field_tag 'settings[custom_email_field]', @settings[:custom_email_field], size: 40 %>
<em class="info"><%= l(:oauth_custom_email_field_info) %></em>
</p>
</div>
</div>
42 changes: 37 additions & 5 deletions assets/javascripts/redmine_oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,46 +40,78 @@ function oauth_set_icon()
icon.addClass(icon_class);
}

function oauth_set_btn_title()
{
let oauth_name = $("input#settings_custom_name").val().trim() ? $("input#settings_custom_name").val().trim() : $("#settings_oauth_name option:selected").val();
let button = $("button#login-oauth-button");
let html = button.html();
html = html.replace(/<b>.*<\/b>/, "<b>" + oauth_name + "</b>");
button.html(html);
}

function oauth_settings_visibility()
{
let div_oauth_options = $("div#oauth_options");
let tenant_id = $("input#settings_tenant_id");
let button = $("button#login-oauth-button");
let tenant_id = $("input#settings_tenant_id");
let oauth_name = $("#settings_oauth_name option:selected").val();
let html = button.html();
$("input#settings_custom_name").val(oauth_name);
oauth_set_btn_title();

$("input#settings_site").val("");
$("input#settings_client_id").val("");
$("input#settings_client_secret").val("");
html = html.replace(/<b>.*<\/b>/, "<b>" + oauth_name + "</b>");
button.html(html);

switch(oauth_name) {
case 'none':
div_oauth_options.hide();
tenant_id.val("");
break;
case 'Azure AD':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').show();
div_oauth_options.find('#oauth_options_tenant').show();
div_oauth_options.find('#oauth_options_custom').hide();
tenant_id.val("");
break;
case 'GitLab':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').show();
div_oauth_options.find('#oauth_options_tenant').hide();
div_oauth_options.find('#oauth_options_custom').hide();
break;
case 'Google':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').show();
div_oauth_options.find('#oauth_options_tenant').hide();
div_oauth_options.find('#oauth_options_custom').hide();
break;
case 'Keycloak':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').show();
div_oauth_options.find('#oauth_options_tenant').show();
div_oauth_options.find('#oauth_options_custom').hide();
tenant_id.val("");
break;
case 'Okta':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').show();
div_oauth_options.find('#oauth_options_tenant').show();
div_oauth_options.find('#oauth_options_custom').hide();
tenant_id.val("default");
break;
case 'Custom':
div_oauth_options.show();
div_oauth_options.find('#oauth_options_site').hide();
div_oauth_options.find('#oauth_options_tenant').hide();
tenant_id.val("");
div_oauth_options.find('#oauth_options_custom').show();
$("input#settings_custom_auth_endpoint").val("");
$("input#settings_custom_token_endpoint").val("");
$("input#settings_custom_profile_endpoint").val("");
$("input#settings_custom_scope").val("openid profile email");
$("input#settings_custom_uid_field").val("preferred_username");
$("input#settings_custom_email_field").val("email");
break;
default:
break;
}
Expand Down
14 changes: 14 additions & 0 deletions config/locales/cs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ cs:
oauth_tenant_id_info: ID adresáře (tenanta)
oauth_button_info: Barva a ikonka (třída Awesome fontu) přihlašovacího tlačítka OAuth (prázdné pro žádné tlačítko)
oauth_login_button: Přihlašovací tlačítko
oauth_custom_name: Provider name
oauth_custom_name_info: Title to be shown on the OAuth login button
oauth_custom_auth_endpoint: Auth endpoint
oauth_custom_auth_endpoint_info: Application Auth endpoint
oauth_custom_token_endpoint: Token endpoint
oauth_custom_token_endpoint_info: Application Token endpoint
oauth_custom_profile_endpoint: Profile endpoint
oauth_custom_profile_endpoint_info: Application Profile endpoint
oauth_custom_scope: OAuth scope
oauth_custom_scope_info: OAuth scope (default - 'openid profile email')
oauth_custom_uid_field: UID field
oauth_custom_uid_field_info: UID field (default - sub)
oauth_custom_email_field: Email field
oauth_custom_email_field_info: Email field (default - email)
14 changes: 14 additions & 0 deletions config/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ de:
oauth_tenant_id_info: Verzeichnis-ID (Mandant)
oauth_button_info: Farbe und Symbol (Awesome-Schriftklasse) des OAuth-Anmeldebuttons (Leer für keinen Button)
oauth_login_button: Anmeldebutton
oauth_custom_name: Provider name
oauth_custom_name_info: Title to be shown on the OAuth login button
oauth_custom_auth_endpoint: Auth endpoint
oauth_custom_auth_endpoint_info: Application Auth endpoint
oauth_custom_token_endpoint: Token endpoint
oauth_custom_token_endpoint_info: Application Token endpoint
oauth_custom_profile_endpoint: Profile endpoint
oauth_custom_profile_endpoint_info: Application Profile endpoint
oauth_custom_scope: OAuth scope
oauth_custom_scope_info: OAuth scope (default - 'openid profile email')
oauth_custom_uid_field: UID field
oauth_custom_uid_field_info: UID field (default - sub)
oauth_custom_email_field: Email field
oauth_custom_email_field_info: Email field (default - email)
14 changes: 14 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ en:
oauth_tenant_id_info: Directory (tenant) ID
oauth_button_info: Colour and icon (Awesome font class) of the OAuth login button (Empty for no button)
oauth_login_button: Login button
oauth_custom_name: Provider name
oauth_custom_name_info: Title to be shown on the OAuth login button
oauth_custom_auth_endpoint: Auth endpoint
oauth_custom_auth_endpoint_info: Application Auth endpoint
oauth_custom_token_endpoint: Token endpoint
oauth_custom_token_endpoint_info: Application Token endpoint
oauth_custom_profile_endpoint: Profile endpoint
oauth_custom_profile_endpoint_info: Application Profile endpoint
oauth_custom_scope: OAuth scope
oauth_custom_scope_info: OAuth scope (default - 'openid profile email')
oauth_custom_uid_field: UID field
oauth_custom_uid_field_info: UID field (default - sub)
oauth_custom_email_field: Email field
oauth_custom_email_field_info: Email field (default - email)
14 changes: 14 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,17 @@ fr:
oauth_tenant_id_info: ID de répertoire (tenant)
oauth_button_info: Couleur et icône (classe Font Awesome) du bouton de connexion via OAuth (Laissez vite pour masquer le bouton)
oauth_login_button: Bouton de connexion
oauth_custom_name: Provider name
oauth_custom_name_info: Title to be shown on the OAuth login button
oauth_custom_auth_endpoint: Auth endpoint
oauth_custom_auth_endpoint_info: Application Auth endpoint
oauth_custom_token_endpoint: Token endpoint
oauth_custom_token_endpoint_info: Application Token endpoint
oauth_custom_profile_endpoint: Profile endpoint
oauth_custom_profile_endpoint_info: Application Profile endpoint
oauth_custom_scope: OAuth scope
oauth_custom_scope_info: OAuth scope (default - 'openid profile email')
oauth_custom_uid_field: UID field
oauth_custom_uid_field_info: UID field (default - sub)
oauth_custom_email_field: Email field
oauth_custom_email_field_info: Email field (default - email)

0 comments on commit e7a55de

Please sign in to comment.