Skip to content

Commit

Permalink
Merge pull request #130 from gate-sso/saml_app_configuration
Browse files Browse the repository at this point in the history
Saml app configuration
  • Loading branch information
sidpub authored Nov 3, 2018
2 parents 330adc0 + ec8f47f commit d8746ab
Show file tree
Hide file tree
Showing 40 changed files with 1,164 additions and 170 deletions.
14 changes: 12 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ rvm:
services:
- redis-server
- mysql
addons:
apt:
sources:
- mysql-5.7-trusty
packages:
- mysql-server
- mysql-client
env:
global:
- GATE_OAUTH_CLIENT_ID=totally_secret_client_id
Expand All @@ -21,17 +28,20 @@ env:
- GATE_DB_PORT=3306
- GATE_DB_USER=root
- GATE_DB_PASSWORD=
- SAML_APPS="datadog"
- secure: Q2/gUeT/Y6IUKsRzgiiE6HGxLcHAzTtVCv6+6TcQnpJL9+HEO06+ISwekNXHRe/2BNMiWzDG5ufqo2YpA1j9h8899KAJZRYDULbbV0o8nrpT2kZSac1ZejBVYb/SrhDk8wrnQxQ061o6SdKpFEEwbIiJDzaqeQkv4tkyw3dEOq6+FRGS/QXj3mPIIArPbNCOtwcvnmg0mGIuPAAxuRZmz4Tuk2F6JdR4LrZstf33mvUYqbTw02Kl7UoErFjGSx2Ti+JPYIVDJ6D8pNCjv5va3awJskcXE5bj0evR5+OiP69GK6T2/UbP+QKwN2J36Pb9RxBKGuEkBTNuduch+h+RMiYk0A8MDO3Sy47i2v8Oj1xTEYqsNm0scmD2utZ93/VqPipYTrxuos7gbC4mdiW3dcMzyrhgaULEJlvalKaSQV41Xex8h/V7NCRvpoYjnyuWVUMQFgGSnE25Xpt1LvP3epcxlEBA9LcndskbEHaWup8mCD2bp+2Zq10iWi/hNnR2IBrj61fApTWBSoNplJMsMZNb3bverQVFFG79Gfr320HWk+eJVahZNFwUYp9VYn17r38nMRdfP9B85hm2ZUEiokzOvEXEKoSa2QVlCNQHk4HGJmfykPn4L8kDnS6LhYV3Yxugxwsl//1iUOwv4+ARMGn/rs13BDOixWXc+GVZIvk=
- secure: hTSsv54GMEfKuZfk5UL3cekNK4ZgEEWwTp2cbfN39ViWBbq4xtXok1jREx4QyhwkNak47ewHuY0rifxPEYkJVJfj+tA/xiGs9BOG73gNEtQYhXXN/ZodXF0Kq3pYOfcVWDDo7oMAUoohkohHK2TA+KY3mfk5sFbxbXHOlNdSn0vXDSa8MgzALoN6+w1oWkC41perODfNS4EYD3gdhwDg4x6QHrmakrt0oOP4PPMCpOWinvkzWq7lBDdhkPSze47BwGilyUDFSJnunSKip88s6DlP4gNj6YYBiT6xGTPLuR76tgEPma9rp25zGvLxH9LsluMXTNuN0L3/6FzVyv0kJgXIwQrpgreQ+B45q3mT6iNom0alyNk3fYDKU59azpH9G0rC0zflmOhW+jssgwyJN08rJN8rFkhpQreD4dgey7+UDjf7qF3rOd0kXmqBvA/3z/aF8Mla/2+EIb1DjyHwnjAcPF2E0/97Gv2eGpZR/PPrQIVN2m8vEe3ce/39c4S/l9OU0G4Dqz9HMqIBG+0qFdS24+egbjaIoOQzO/eJwG/eew4ncvaz/ES8qCDtvFNeKR+QnfxcbJysybrxDNTqt3cBGTeotIdZxIB3rYK63+s+dvzggm09vBMafoP7zyWzD0xjSES7m+Gv9V8Jlvc7h5JSWrkmAgLmgnqt7FpI7hs=
- secure: KtmItMzRHfZEPS54hTnYXNAWsqxCZZMtmxamJPcr2SVP+pzM/25eEF3M2b0JZECFRtW3xPBGita+4BjH8IY4NljH0IDVhPPKQsMHaVKtaqEeiTCRXCqkJd0DMUDeqyRcccwPDJSy9HeZns6E+zQDCGaC/tmFwDUWy5BYpairWd7sdw436iOeTmQ2fJ8SQ9lBr9LGpk8NwDmkYqg14fnOraIhw70tiWv9Wn82mEv+OwY4iKphOv2ZXEBeJYitoT1LQmhnaVvNvax16TYIY3Mxh89Oy2gVkKCgvbR9q1NmAIiWmMTyCLWxF0bd6A6Q+dHDDaQZF0pDsQqe83rnoA0xuaJUF9dh+ahvW0bn0aVFIa8tWgiBEMXWxHEDuEyfCWFis9vf3uj1xJl0SV0ktE5oIRzaF/0cTQorAwRy0UpN1HxK1yB9aITCad/BJ9ERK8MXYnfzC65jn2zHuQMjBz9Aeig4sgLc4IgtGM2DzabsIkhYG3ygL1TYaXXSj5Mo2KDwOuaZ46C7B6qxlzcesPmSnM3KF1CBatRZQK5tjsMm5GnxXKKtqg/udGtOA2fELlNolFsojtpmO4A79TAnebRUpEsU2vP0da1x7yTD5+2NWg6dnvq7tA3c5b8qBK2cAMnCHS0gmjaN3RYeFhLYO55dHDdmx/DNyQQ1V/YEkuisy80=
- COMMIT=${TRAVIS_COMMIT::8}
- DOCKER_COMPOSE_VERSION=1.11.2
before_install:
- sudo mysql_upgrade -u root
- sudo service mysql restart
- mysql -e 'CREATE DATABASE IF NOT EXISTS gate_test;'
- gem install bundler
script:
- bundle package --all
- bundle install --binstubs --local
- bundle install --binstubs --local
- bundle exec rake db:migrate
- bundle exec rake spec
- bundle exec rake assets:precompile RAILS_ENV=production
Expand All @@ -48,7 +58,7 @@ deploy:
skip_cleanup: true
api_key:
secure: VWDGnrtrECoeJBATfe71HdpvnD15IKTkHWq/cQDfo9FTrm005ngTusQpW0eim76tSTMcJ1OBLoE9aAkd4Szi00TWenNPaAWHtgodcvNXxjqyZEtznRmtZW/vSk2H+iwJxJZoPDMZqStjmmSoD0dA1t2GLGltFzeJ5Y409YeroLUsVdRcTJY0mvQYbuLt1aZCu76gY5nB01yH7ib4ykZllJQbkyX57TKBYSLoQVUQ3hqo9BLUoROknHSfFGBHjSN9D3zIqKoh0XDOuTnyMHB+zMGmjjJbHMx5Z2eW1NW1HvpqDUOPl8uRnUEoCCfujA7OUlGgdadRBeUJObzpNkpQUNLEh5zIIr9NAZzjunzYkMiMZIseTNflJ6HOajld2Bcgz3PcbzM8hcIFog5loE7CBLWEzDoOIY/B75NYuHPIzRzTbgw7jf8XdfypCNMm0RLWiCXiDmuDMcNPZT9NrrheNGFz1CDmWkwpJmUTIv8J13J2Ux9ex1NY9iSRD8rgJ+bLOfp/u1nJWjACki8zq2/vffm2oUWz/R7q23Keq5Itddpe3mJUyFjokTUZPNSAlC45rF+rgK4ka7yJb+ZZAOaq/N8iIfVkgnfviWtaPQzAWRkO8J8Wzt1GrfQpNlo2BMM6Cpy0iV9ANYqAVYerImAopMWlzQmjbtt8P+xmmYA0FIw=
file_glob: true
file_glob: true
file: $TRAVIS_BUILD_DIR/*.tar.gz
on:
repo: gate-sso/gate
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gem 'countries', require: 'countries/global'
gem 'devise'
gem 'figaro'
gem 'font-awesome-rails'
gem 'httparty'
gem 'jbuilder'
gem 'jquery-rails'
gem 'mysql2', '~> 0.4.10'
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ GEM
hashdiff (0.3.7)
hashie (3.5.7)
hirb (0.7.3)
httparty (0.16.2)
multi_xml (>= 0.5.2)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
Expand Down Expand Up @@ -357,6 +359,7 @@ DEPENDENCIES
faker
figaro
font-awesome-rails
httparty
jbuilder
jquery-rails
mock_redis
Expand Down
Binary file added app/assets/images/saml_configure_datadog_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_05.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_08.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/assets/images/saml_configure_datadog_09.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,8 @@ a:hover {
color: blue;
background: none;
}
.table-responsive { overflow-x: inherit; }


#configAppTabsContent .tab-pane { padding-top: 20px; }
#configAppTabsContent ol li { margin-top: 10px; }
#configAppTabsContent li > ol { margin-bottom: 10px; }
62 changes: 62 additions & 0 deletions app/clients/data_dog_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
class DataDogClient
include HTTParty
base_uri 'https://api.datadoghq.com/api/v1'

def initialize(app_key, api_key)
@base_path = 'https://api.datadoghq.com/api/v1'
@app_key = app_key
@api_key = api_key
@headers = {
'Content-Type' => 'application/json',
'Accept' => 'application/json',
}
end

def get_user(email)
url = append_auth("/user/#{email}")
response = self.class.get(url, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end

def new_user(email)
url = append_auth('/user')
response = self.class.post(url, body: { handle: email }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end

def activate_user(email)
url = append_auth("/user/#{email}")
response = self.class.put(url, body: { email: email, disabled: false }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end

def deactivate_user(email)
url = append_auth("/user/#{email}")
response = self.class.put(url, body: { email: email, disabled: true }.to_json, headers: @headers)
if response.success?
JSON.parse(response.body)['user']
else
{}
end
end

private

def append_auth(str)
auth_str = "api_key=#{@api_key}&application_key=#{@app_key}"
str += str.include?('?') ? "&#{auth_str}" : "?#{auth_str}"
str
end
end
87 changes: 75 additions & 12 deletions app/controllers/organisations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
class OrganisationsController < ApplicationController
before_action :load_org, only: %i(
config_saml_app update show setup_saml save_config_saml_app
remove_user_saml_app add_user_saml_app
)
before_action :validate_app_name, only: %i(
config_saml_app save_config_saml_app
remove_user_saml_app add_user_saml_app
)

def index
render :index, locals: { org_list: Organisation.all }
end
Expand All @@ -7,6 +16,53 @@ def new
render :new, locals: { org: Organisation.new }
end

def config_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
config = saml_app.config
users = config.persisted? ? config.group.users : []
render :config_saml_app, locals: {
org: @org,
saml_config: config,
app_name: app_name,
users: users,
}
end

def save_config_saml_app
app_name = params[:app_name]
saml_app_config = params[:saml_app_config]
saml_app = app_name.titleize.constantize.new(@org.id)
saml_app.save_config(saml_app_config[:sso_url], params[:config])
flash[:success] = 'Configuration saved successfully'
redirect_to organisation_config_saml_app_path(
app_name: app_name,
organisation_id: @org.id
)
end

def remove_user_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
if saml_app.remove_user(params[:email])
flash[:success] = 'User removed successfullly'
else
flash[:error] = 'Issue removing the user'
end
redirect_to organisation_config_saml_app_path
end

def add_user_saml_app
app_name = params[:app_name]
saml_app = app_name.titleize.constantize.new(@org.id)
if saml_app.add_user(params[:email])
flash[:success] = 'User added successfullly'
else
flash[:error] = 'Issue adding the user'
end
redirect_to organisation_config_saml_app_path
end

def create
org = Organisation.setup(organisation_params.to_h || {})
if org.errors.blank?
Expand All @@ -19,27 +75,25 @@ def create
end

def update
org = load_org
org.update_profile(organisation_params.to_h || {})
if org.errors.blank?
@org.update_profile(organisation_params.to_h || {})
if @org.errors.blank?
flash[:success] = 'Successfully updated organisation'
redirect_to organisations_path
else
flash[:errors] = org.errors.full_messages
render :show, locals: { org: org }
flash[:errors] = @org.errors.full_messages
render :show, locals: { org: @org }
end
end

def show
render :show, locals: { org: load_org }
render :show, locals: { org: @org }
end

def setup_saml
org = load_org
if org.saml_setup?
if @org.saml_setup?
flash[:errors] = 'SAML Certificates Already Setup'
else
load_org.setup_saml_certs
@org.setup_saml_certs
flash[:success] = 'Successfully setup SAML Certificates'
end
redirect_to organisations_path
Expand All @@ -48,9 +102,18 @@ def setup_saml
private

def load_org
org = Organisation.where(params[:id]).first
redirect_to organisations_path if org.blank?
org
id = params[:id] || params[:organisation_id]
@org = Organisation.where(id: id).first
if @org.blank?
redirect_to organisations_path
end
end

def validate_app_name
saml_apps = Figaro.env.saml_apps.split(',').map(&:downcase)
unless saml_apps.include?(params[:app_name].downcase)
redirect_to organisation_path(id: params[:organisation_id])
end
end

def organisation_params
Expand Down
11 changes: 11 additions & 0 deletions app/controllers/saml_idp_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ class SamlIdpController < SamlIdp::IdpController
layout false
before_action :setup_saml_configuration

def show
xml_content = SamlIdp.metadata.signed
if params.key?(:download)
send_data xml_content,
type: 'text/xml',
filename: 'metadata.xml'
else
render xml: xml_content
end
end

private

def idp_authenticate(email, password)
Expand Down
35 changes: 35 additions & 0 deletions app/lib/datadog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class Datadog < SamlApp

def initialize(org_id)
@app_name = 'datadog'
super(org_id)
if @config.persisted?
@client = DataDogClient.new(
@config.config['app_key'],
@config.config['api_key']
)
else
@config.config = { app_key: '', api_key: '' }
end
end

def save_config(sso_url, config = {})
@config.config = @config.config.merge(config)
super(sso_url, config)
end

def add_user(email)
user_detail_response = @client.get_user(email)
response = if user_detail_response.eql?({})
@client.new_user(email)
else
@client.activate_user(email)
end
super(email) unless response.eql?({})
end

def remove_user(email)
response = @client.deactivate_user(email)
super(email) unless response.eql?({})
end
end
37 changes: 37 additions & 0 deletions app/lib/saml_app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class SamlApp

attr_accessor :config, :app_name

def initialize(org_id)
@config = SamlAppConfig.find_or_initialize_by(
app_name: @app_name, organisation_id: org_id
)
end

def save_config(sso_url, config = {})
unless @config.persisted?
group_name = "#{@config.organisation.slug}_saml_#{app_name}_users"
@config.group = Group.find_or_create_by(name: group_name)
end
@config.sso_url = sso_url
@config.save
end

def add_user(email)
user = User.where(email: email).first
unless user.blank?
@config.group.add_user(user.id)
return true
end
false
end

def remove_user(email)
user = User.where(email: email).first
unless user.blank?
@config.group.remove_user(user.id)
return true
end
false
end
end
10 changes: 10 additions & 0 deletions app/models/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,14 @@ def self.get_default_sysadmin_group_for_host sysadmins_login_ids, default_admins
sysadmin_group[:gr_passwd] = "x"
return sysadmin_group
end

def add_user(user_id)
unless group_associations.map(&:user_id).include?(user_id)
group_associations.create(user_id: user_id)
end
end

def remove_user(user_id)
group_associations.where(user_id: user_id).delete_all
end
end
10 changes: 10 additions & 0 deletions app/models/saml_app_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class SamlAppConfig < ApplicationRecord
belongs_to :group
belongs_to :organisation

def self.get_config(app_name, org_id)
SamlAppConfig.find_or_initialize_by(
app_name: app_name, organisation_id: org_id
)
end
end
7 changes: 7 additions & 0 deletions app/views/organisations/config_saml_app.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.container.col-md-8
.row.mb-3.mt-2
.col-md-12
h5 Configure #{app_name.titleize}
.row.mb-3.mt-2
.col-md-12
= render partial: "organisations/saml_apps/#{app_name}", locals: {org: org, app_name: app_name, saml_config: saml_config, users: users}
Loading

0 comments on commit d8746ab

Please sign in to comment.