Add redmine community auth plugin

Written by Alex Shulgin (ash at commandprompt.com)
This commit is contained in:
Magnus Hagander
2012-05-25 13:10:58 +02:00
parent 4102dd72de
commit 7970aaf38c
9 changed files with 152 additions and 0 deletions

View File

@ -0,0 +1,3 @@
= pgcommunityauth
Description goes here

View File

@ -0,0 +1,3 @@
<p>
PostgreSQL community auth login page.
</p>

View File

@ -0,0 +1,12 @@
<p>
<%= label_tag :settings_authsite_id, "Auth site ID" %>
<%= text_field_tag 'settings[authsite_id]', settings['authsite_id'], :size => 5 %>
</p>
<p>
<%= label_tag :settings_cipher_key, "Cipher key (Base64)" %>
<%= text_field_tag 'settings[cipher_key]', settings['cipher_key'] %>
</p>
<p>
<%= label_tag :settings_default_url, "Default URL (/)" %>
<%= text_field_tag 'settings[default_url]', settings['default_url'] %>
</p>

View File

@ -0,0 +1,3 @@
# English strings go here for Rails i18n
en:
my_label: "My label"

View File

@ -0,0 +1,3 @@
ActionController::Routing::Routes.draw do |map|
map.pgcommunityauth '/pgcommunityauth', :controller => 'account', :action => 'pgcommunityauth'
end

View File

@ -0,0 +1,17 @@
require 'redmine'
require 'dispatcher'
Dispatcher.to_prepare do
require_dependency 'account_controller'
AccountController.send(:include, RedminePgcommunityauth::AccountControllerPatch)
end
Redmine::Plugin.register :redmine_pgcommunityauth do
name 'Redmine Pgcommunityauth plugin'
author 'Alex Shulgin <ash@commandprompt.com>'
description ''
version '0.0.1'
settings :default => {}, :partial => 'settings/redmine_pgcommunityauth_settings'
end

View File

@ -0,0 +1,2 @@
# English strings go here
my_label: "My label"

View File

@ -0,0 +1,104 @@
require 'base64'
require 'openssl' # aes gem doesn't let us disable PKCS#5 padding
module RedminePgcommunityauth
module AccountControllerPatch
unloadable
class AuthTokenExpiredError < RuntimeError; end
class InvalidAuthTokenError < RuntimeError; end
def self.included(base)
base.class_eval do
alias_method_chain :login, :pgcommunityauth
alias_method_chain :logout, :pgcommunityauth
end
end
def login_with_pgcommunityauth
redirect_to pgcommunityauth_login_url
end
def logout_with_pgcommunityauth
logout_user
redirect_to pgcommunityauth_logout_url
end
# GET /pgcommunityauth
def pgcommunityauth
if params[:s] == 'logout'
flash[:notice] = "Successfully logged out from PG community sites."
return
end
data = (params[:d] || "").tr('-_', '+/')
iv = (params[:i] || "").tr('-_', '+/')
qs = aes_decrypt(data, iv).rstrip
auth = Rack::Utils.parse_query(qs)
# check auth hash for mandatory keys
raise InvalidAuthTokenError.new unless %w(t u f l e).all?{ |x| auth.keys.include?(x) }
# check auth token timestamp: issued 10 seconds ago or less
raise AuthTokenExpiredError.new unless Time.now.to_i <= auth['t'].to_i + 10
# prepare attrs for create or update
attrs = {
:firstname => auth['f'],
:lastname => auth['l'],
:mail => auth['e']
}
if user = User.find_by_login(auth['u'])
user.update_attributes! attrs
else
user = User.new(attrs)
# can't pass protected attr in new/create
user.login = auth['u']
user.save!
end
params[:back_url] = auth['su'] || pgcommunityauth_settings[:default_url]
successful_authentication(user)
rescue OpenSSL::Cipher::CipherError
flash[:error] = "Invalid PG communityauth message received."
rescue InvalidAuthTokenError
flash[:error] = "Invalid PG communityauth token received."
rescue AuthTokenExpiredError
flash[:error] = "PG community auth token expired."
end
private
def pgcommunityauth_settings
Setting['plugin_redmine_pgcommunityauth']
end
def pgcommunityauth_base_url
"https://www.postgresql.org/account/auth/#{pgcommunityauth_settings[:authsite_id]}"
end
def pgcommunityauth_login_url
"#{pgcommunityauth_base_url}/"
end
def pgcommunityauth_logout_url
"#{pgcommunityauth_base_url}/logout/"
end
def aes_decrypt(data, iv)
key = Base64.decode64(pgcommunityauth_settings[:cipher_key])
cipher = OpenSSL::Cipher.new("AES-#{key.size*8}-CBC")
cipher.decrypt
# this is the key point here, otherwise we could use
# AES.decrypt()
cipher.padding = 0
cipher.key = key
cipher.iv = Base64.decode64(iv)
cipher.update(Base64.decode64(data)) + cipher.final
end
end
end

View File

@ -0,0 +1,5 @@
# Load the normal Rails helper
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
# Ensure that we are using the temporary fixture path
Engines::Testing.set_fixture_path