Init backend of generic external credentials.
This commit is contained in:
parent
9a702b528c
commit
23bb04566d
9 changed files with 183 additions and 151 deletions
1
Gemfile
1
Gemfile
|
@ -33,7 +33,6 @@ gem 'omniauth-linkedin'
|
||||||
gem 'omniauth-google-oauth2'
|
gem 'omniauth-google-oauth2'
|
||||||
|
|
||||||
gem 'twitter'
|
gem 'twitter'
|
||||||
gem 'twitter_oauth'
|
|
||||||
gem 'koala'
|
gem 'koala'
|
||||||
gem 'mail', '~> 2.5.0'
|
gem 'mail', '~> 2.5.0'
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,7 @@ GEM
|
||||||
simplecov-rcov (0.2.3)
|
simplecov-rcov (0.2.3)
|
||||||
simplecov (>= 0.4.1)
|
simplecov (>= 0.4.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
spring (1.5.0)
|
spring (1.6.0)
|
||||||
sprockets (3.5.2)
|
sprockets (3.5.2)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
|
@ -307,10 +307,6 @@ GEM
|
||||||
memoizable (~> 0.4.0)
|
memoizable (~> 0.4.0)
|
||||||
naught (~> 1.0)
|
naught (~> 1.0)
|
||||||
simple_oauth (~> 0.3.0)
|
simple_oauth (~> 0.3.0)
|
||||||
twitter_oauth (0.4.94)
|
|
||||||
json (>= 1.8.0)
|
|
||||||
mime-types (>= 1.16)
|
|
||||||
oauth (>= 0.4.7)
|
|
||||||
tzinfo (1.2.2)
|
tzinfo (1.2.2)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (2.7.2)
|
uglifier (2.7.2)
|
||||||
|
@ -373,7 +369,6 @@ DEPENDENCIES
|
||||||
test-unit
|
test-unit
|
||||||
therubyracer
|
therubyracer
|
||||||
twitter
|
twitter
|
||||||
twitter_oauth
|
|
||||||
uglifier
|
uglifier
|
||||||
writeexcel
|
writeexcel
|
||||||
|
|
||||||
|
|
75
app/controllers/external_credentials_controller.rb
Normal file
75
app/controllers/external_credentials_controller.rb
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ExternalCredentialsController < ApplicationController
|
||||||
|
before_action :authentication_check
|
||||||
|
|
||||||
|
def index
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
model_index_render(ExternalCredential, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
model_show_render(ExternalCredential, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
|
||||||
|
# try access
|
||||||
|
begin
|
||||||
|
attributes = ExternalCredential.app_verify(params)
|
||||||
|
model_create_render(ExternalCredential, { name: params[:provider].downcase, credentials: attributes })
|
||||||
|
return
|
||||||
|
rescue => e
|
||||||
|
render json: { error: e.message }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
|
||||||
|
# try access
|
||||||
|
begin
|
||||||
|
attributes = ExternalCredential.app_verify(params)
|
||||||
|
model_update_render(ExternalCredential, { name: params[:provider].downcase, credentials: attributes })
|
||||||
|
return
|
||||||
|
rescue => e
|
||||||
|
render json: { error: e.message }, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
model_destory_render(ExternalCredential, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_account
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
provider = params[:provider].downcase
|
||||||
|
|
||||||
|
attributes = ExternalCredential.request_account_to_link(provider, callback_url(provider))
|
||||||
|
|
||||||
|
session[:request_token] = attributes[:request_token]
|
||||||
|
|
||||||
|
redirect_to attributes[:authorize_url]
|
||||||
|
end
|
||||||
|
|
||||||
|
def callback
|
||||||
|
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
||||||
|
provider = params[:provider].downcase
|
||||||
|
|
||||||
|
channel = ExternalCredential.link_account(provider, session[:request_token], params)
|
||||||
|
|
||||||
|
session[:request_token] = nil
|
||||||
|
|
||||||
|
render json: channel
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def callback_url(provider)
|
||||||
|
"#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/external_credentials/#{provider}/callback"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,129 +0,0 @@
|
||||||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
|
||||||
|
|
||||||
require 'twitter_oauth'
|
|
||||||
|
|
||||||
class ExternalCredentialsTwitterController < ApplicationController
|
|
||||||
before_action :authentication_check
|
|
||||||
|
|
||||||
def index
|
|
||||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
|
||||||
|
|
||||||
twitter_credential = ExternalCredential.find_by(name: 'Twitter')
|
|
||||||
|
|
||||||
# TODO: refactor
|
|
||||||
result = {
|
|
||||||
# consumer_key: nil,
|
|
||||||
# consumer_secret: nil,
|
|
||||||
}
|
|
||||||
if !twitter_credential.nil?
|
|
||||||
|
|
||||||
# p twitter_credential.credentials.inspect
|
|
||||||
|
|
||||||
result[:consumer_key] = twitter_credential.credentials[:consumer_key]
|
|
||||||
result[:consumer_secret] = twitter_credential.credentials[:consumer_secret]
|
|
||||||
result[:authorize_url] = twitter_credential.credentials[:authorize_url]
|
|
||||||
end
|
|
||||||
|
|
||||||
render json: result, status: :ok
|
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
|
||||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
|
||||||
model_show_render(ExternalCredential, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
|
||||||
|
|
||||||
credentials = handle_credentials(params)
|
|
||||||
|
|
||||||
# create object
|
|
||||||
twitter_credential = ExternalCredential.new( name: 'Twitter', credentials: credentials )
|
|
||||||
|
|
||||||
# save object
|
|
||||||
twitter_credential.save!
|
|
||||||
|
|
||||||
redirect_to credentials[:authorize_url]
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
|
||||||
|
|
||||||
credentials = handle_credentials(params)
|
|
||||||
|
|
||||||
# find object
|
|
||||||
twitter_credential = ExternalCredential.find(params[:id])
|
|
||||||
|
|
||||||
# update object
|
|
||||||
twitter_credential.update_attributes!( name: 'Twitter', credentials: credentials )
|
|
||||||
|
|
||||||
redirect_to credentials.authorize_url
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
return if deny_if_not_role(Z_ROLENAME_ADMIN)
|
|
||||||
model_destory_render(ExternalCredential, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth
|
|
||||||
# https://zammad.tld/twitter_auth?oauth_token=uP15WgAAAAAAivjgAAABUSUkP5Y&oauth_verifier=OlKro1xj7gBQ5cwdvlcYQEniiEm1THsd
|
|
||||||
params[:oauth_token]
|
|
||||||
params[:oauth_verifier]
|
|
||||||
|
|
||||||
params.require(:name, :oauth_token, :oauth_verifier)
|
|
||||||
params.permit(:name, :oauth_token, :oauth_verifier)
|
|
||||||
|
|
||||||
twitter_credential = ExternalCredential.find_by( name: 'Twitter' )
|
|
||||||
|
|
||||||
if ( twitter_credential[:credentials][:oauth_token] != params[:oauth_token] )
|
|
||||||
# TODO: ERROR
|
|
||||||
end
|
|
||||||
|
|
||||||
access_token = client.authorize(
|
|
||||||
twitter_credential[:credentials][:oauth_token],
|
|
||||||
twitter_credential[:credentials][:oauth_token_secret],
|
|
||||||
oauth_verifier: params[:oauth_verifier]
|
|
||||||
)
|
|
||||||
|
|
||||||
credentials = {
|
|
||||||
consumer_key: twitter_credential[:credentials][:consumer_key],
|
|
||||||
consumer_secret: twitter_credential[:credentials][:consumer_secret],
|
|
||||||
access_token: access_token.token,
|
|
||||||
access_token_secret: access_token.secret,
|
|
||||||
}
|
|
||||||
|
|
||||||
twitter_credential.update_attributes!(credentials: credentials )
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
redirect_to "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#admin/path/external_credentials_twitter"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def handle_credentials(params)
|
|
||||||
|
|
||||||
params.require(:consumer_key)
|
|
||||||
params.require(:consumer_secret)
|
|
||||||
|
|
||||||
params.permit(:consumer_key, :consumer_secret)
|
|
||||||
|
|
||||||
credentials = {
|
|
||||||
consumer_key: params[:consumer_key],
|
|
||||||
consumer_secret: params[:consumer_secret],
|
|
||||||
}
|
|
||||||
|
|
||||||
client = TwitterOAuth::Client.new(
|
|
||||||
consumer_key: credentials[:consumer_key],
|
|
||||||
consumer_secret: credentials[:consumer_secret],
|
|
||||||
)
|
|
||||||
|
|
||||||
# TODO: improve callback URL
|
|
||||||
request_token = client.request_token(oauth_callback: "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#{Rails.configuration.api_path}/external_credentials_twitter/Twitter/auth")
|
|
||||||
|
|
||||||
credentials[:oauth_token] = request_token.token
|
|
||||||
credentials[:oauth_token_secret] = request_token.secret
|
|
||||||
credentials[:authorize_url] = request_token.authorize_url
|
|
||||||
|
|
||||||
credentials
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,4 +1,28 @@
|
||||||
class ExternalCredential < ActiveRecord::Base
|
class ExternalCredential < ApplicationModel
|
||||||
|
include ApplicationLib
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
store :credentials
|
store :credentials
|
||||||
|
|
||||||
|
def self.app_verify(params)
|
||||||
|
backend = load_backend(params[:provider])
|
||||||
|
backend.app_verify(params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.request_account_to_link(provider, callback)
|
||||||
|
backend = load_backend(provider)
|
||||||
|
backend.request_account_to_link(callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.link_account(provider, request_token, params)
|
||||||
|
backend = load_backend(provider)
|
||||||
|
backend.link_account(request_token, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.load_backend(provider)
|
||||||
|
adapter = "ExternalCredential::#{provider.camelcase}"
|
||||||
|
require "#{adapter.to_filename}"
|
||||||
|
load_adapter(adapter)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
15
config/routes/external_credentials.rb
Normal file
15
config/routes/external_credentials.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
# CRUD
|
||||||
|
match api_path + '/external_credentials', to: 'external_credentials#index', via: :get
|
||||||
|
match api_path + '/external_credentials/:id', to: 'external_credentials#show', via: :get
|
||||||
|
match api_path + '/external_credentials', to: 'external_credentials#create', via: :post
|
||||||
|
match api_path + '/external_credentials/:id', to: 'external_credentials#update', via: :put
|
||||||
|
match api_path + '/external_credentials/:id', to: 'external_credentials#destroy', via: :delete
|
||||||
|
|
||||||
|
# callback URL
|
||||||
|
match api_path + '/external_credentials/:provider/link_account', to: 'external_credentials#link_account', via: :get
|
||||||
|
match api_path + '/external_credentials/:provider/callback', to: 'external_credentials#callback', via: :get
|
||||||
|
|
||||||
|
end
|
|
@ -1,14 +0,0 @@
|
||||||
Zammad::Application.routes.draw do
|
|
||||||
api_path = Rails.configuration.api_path
|
|
||||||
|
|
||||||
# CRUD
|
|
||||||
match api_path + '/external_credentials_twitter', to: 'external_credentials_twitter#index', via: :get
|
|
||||||
match api_path + '/external_credentials_twitter/:id', to: 'external_credentials_twitter#show', via: :get
|
|
||||||
match api_path + '/external_credentials_twitter', to: 'external_credentials_twitter#create', via: :post
|
|
||||||
match api_path + '/external_credentials_twitter/:id', to: 'external_credentials_twitter#update', via: :put
|
|
||||||
match api_path + '/external_credentials_twitter/:id', to: 'external_credentials_twitter#destroy', via: :delete
|
|
||||||
|
|
||||||
# callback URL
|
|
||||||
match api_path + '/external_credentials_twitter/:name/auth', to: 'external_credentials_twitter#auth', via: :get
|
|
||||||
|
|
||||||
end
|
|
|
@ -128,6 +128,7 @@ returns
|
||||||
'Channels' => 'Channel',
|
'Channels' => 'Channel',
|
||||||
'EmailAddresses' => 'EmailAddress',
|
'EmailAddresses' => 'EmailAddress',
|
||||||
'Signatures' => 'Signature',
|
'Signatures' => 'Signature',
|
||||||
|
'Groups' => 'Group',
|
||||||
}
|
}
|
||||||
model_map.each {|map_name, model|
|
model_map.each {|map_name, model|
|
||||||
next if !auto_wizard_hash[map_name]
|
next if !auto_wizard_hash[map_name]
|
||||||
|
|
66
lib/external_credential/twitter.rb
Normal file
66
lib/external_credential/twitter.rb
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
class ExternalCredential::Twitter
|
||||||
|
|
||||||
|
def self.app_verify(params)
|
||||||
|
attributes = {
|
||||||
|
consumer_key: params[:consumer_key],
|
||||||
|
consumer_secret: params[:consumer_secret],
|
||||||
|
}
|
||||||
|
request_account_to_link('', attributes)
|
||||||
|
attributes
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.request_account_to_link(callback_url, credentials = {})
|
||||||
|
external_credential = ExternalCredential.find_by(name: 'twitter')
|
||||||
|
consumer = OAuth::Consumer.new(
|
||||||
|
credentials[:consumer_key] || external_credential.credentials[:consumer_key],
|
||||||
|
credentials[:consumer_secret] || external_credential.credentials[:consumer_secret], {
|
||||||
|
site: 'https://api.twitter.com'
|
||||||
|
})
|
||||||
|
request_token = consumer.get_request_token(oauth_callback: callback_url)
|
||||||
|
{
|
||||||
|
request_token: request_token,
|
||||||
|
authorize_url: request_token.authorize_url,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.link_account(request_token, params)
|
||||||
|
fail if request_token.params[:oauth_token] != params[:oauth_token]
|
||||||
|
|
||||||
|
external_credential = ExternalCredential.find_by(name: 'twitter')
|
||||||
|
access_token = request_token.get_access_token(oauth_verifier: params[:oauth_verifier])
|
||||||
|
client = Twitter::REST::Client.new(
|
||||||
|
consumer_key: external_credential.credentials[:consumer_key],
|
||||||
|
consumer_secret: external_credential.credentials[:consumer_secret],
|
||||||
|
access_token: access_token.token,
|
||||||
|
access_token_secret: access_token.secret,
|
||||||
|
)
|
||||||
|
user = client.user
|
||||||
|
|
||||||
|
# create channel
|
||||||
|
Channel.create(
|
||||||
|
area: 'Twitter::Account',
|
||||||
|
options: {
|
||||||
|
adapter: 'twitter',
|
||||||
|
user: {
|
||||||
|
id: user.id,
|
||||||
|
screen_name: user.screen_name,
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
external_credential_id: external_credential.id,
|
||||||
|
oauth_token: access_token.token,
|
||||||
|
oauth_token_secret: access_token.secret,
|
||||||
|
},
|
||||||
|
sync: {
|
||||||
|
search: [],
|
||||||
|
mentions: {},
|
||||||
|
direct_messages: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue