diff --git a/.rspec b/.rspec index 83e16f80..b83d9b7a 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1,3 @@ --color +--format documentation --require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml index cdd1b599..ecc9383d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -358,7 +358,7 @@ Style/StringLiterals: Style/TrailingCommaInArguments: Description: 'Checks for trailing comma in argument lists.' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' - EnforcedStyleForMultiline: comma + EnforcedStyleForMultiline: no_comma SupportedStylesForMultiline: - comma - consistent_comma diff --git a/Gemfile b/Gemfile index 19c9ef94..9ab1ce0c 100755 --- a/Gemfile +++ b/Gemfile @@ -17,7 +17,6 @@ gem 'puma' gem 'rails', '4.2.8' gem 'redis' gem 'rotp' -gem 'saml_idp', git: 'https://github.com/gate-sso/saml_idp.git' gem 'sass-rails' gem 'sdoc', group: :doc gem 'slim-rails' diff --git a/Gemfile.lock b/Gemfile.lock index d40a86f4..f6f02532 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,3 @@ -GIT - remote: https://github.com/gate-sso/saml_idp.git - revision: cd646cbb9baf9af05df87af33d5368c74713f46c - specs: - saml_idp (0.7.2) - activesupport (>= 3.2) - builder (>= 3.0) - nokogiri (>= 1.6.2) - uuid (>= 2.3) - GEM remote: https://rubygems.org/ specs: @@ -130,8 +120,6 @@ GEM loofah (2.2.2) crass (~> 1.0.2) nokogiri (>= 1.5.9) - macaddr (1.7.1) - systemu (~> 2.6.2) mail (2.7.0) mini_mime (>= 0.1.1) method_source (0.9.0) @@ -291,7 +279,6 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - systemu (2.6.5) temple (0.8.0) term-ansicolor (1.2.2) tins (~> 0.8) @@ -308,8 +295,6 @@ GEM uglifier (4.1.11) execjs (>= 0.3.0, < 3) unicode-display_width (1.4.0) - uuid (2.3.9) - macaddr (~> 1.0) warden (1.2.7) rack (>= 1.0) web-console (3.3.0) @@ -355,7 +340,6 @@ DEPENDENCIES rspec-rails rubocop rubocop-rspec - saml_idp! sass-rails sdoc shoulda-matchers diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 197d5e18..0607ccf1 100755 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -26,7 +26,9 @@ * https://github.com/ladjs/bootstrap-social */ @import "bootstrap-social"; - +a.btn { color: white!important; } +.form-group .field_with_errors { display: block; background: none; } +.form-group .field_with_errors label::after { content: ' *'; color: red; } body { font-family: 'Roboto', 'Lato', sans-serif; } @@ -36,7 +38,7 @@ body { min-width: 768px; } -a:visited { +a:visited { color: blue; } /* mouse over link */ diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb new file mode 100644 index 00000000..1f9d041e --- /dev/null +++ b/app/controllers/organisations_controller.rb @@ -0,0 +1,48 @@ +class OrganisationsController < ApplicationController + def index + render :index, locals: { org_list: Organisation.all } + end + + def new + render :new, locals: { org: Organisation.new } + end + + def create + org = Organisation.setup(organisation_params.to_h || {}) + if org.errors.blank? + flash[:success] = 'Successfully created organisation' + redirect_to organisations_path + else + flash[:errors] = org.errors.full_messages + redirect_to new_organisation_path + end + end + + def update + org = load_org + 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 + redirect_to organisation_path(org) + end + end + + def show + render :show, locals: { org: load_org } + end + + private + + def load_org + org = Organisation.where(params[:id]).first + redirect_to organisations_path if org.blank? + org + end + + def organisation_params + params.require(:organisation).permit(:name, :url, :email_domain) + end +end diff --git a/app/controllers/saml_idp_controller.rb b/app/controllers/saml_idp_controller.rb deleted file mode 100755 index b6622d93..00000000 --- a/app/controllers/saml_idp_controller.rb +++ /dev/null @@ -1,99 +0,0 @@ -class SamlIdpController < SamlIdp::IdpController - before_filter :is_saml_enabled, :except => [:add_saml_sp, :get_saml_sp] - before_filter :authenticate_user!, :except => [:create, :add_saml_sp, :get_saml_sp] unless Rails.env.development? - - def show - if current_user.admin? - render xml: SamlIdp.metadata.signed - else - respond_to do |format| - format.html {render :file => "#{Rails.root}/public/404", :layout => false, :status => :not_found} - format.xml {head :not_found} - format.any {head :not_found} - end - end - end - - def create - unless params[:email].blank? && params[:password].blank? - person = idp_authenticate(params[:email], params[:password]) - if person.nil? - @saml_idp_fail_msg = "Incorrect email or password." - else - @saml_response = idp_make_saml_response(person) - render :template => "saml_idp/idp/saml_post", :layout => false - return - end - end - render :template => "saml_idp/new" - end - - def idp_authenticate(username, token) - if User.find_and_check_user username, token - return User.get_user(username) - end - return false - end - - private :idp_authenticate - - def idp_make_saml_response(found_user) - encode_response found_user - end - - private :idp_make_saml_response - - def add_saml_sp - if AccessToken.valid_token(params[:access_token]) - @sp = SamlServiceProvider.find_or_create_by(:name => params[:name], :sso_url => params[:sso_url], :metadata_url => params[:metadata_url]) - update_saml_idp_config - render json: @sp, status: :ok - else - render json: {"error": "Unauthorized user"}, status: :unauthorized - end - end - - def update_saml_idp_config - SamlIdp.configure do |config| - service_providers = {} - SamlServiceProvider.find_each do |sp| - service_providers[sp.sso_url] = { - :fingerprint => Figaro.env.GATE_SAML_IDP_FINGERPRINT, - :metadata_url => sp.metadata_url - } - end - config.service_provider.finder = ->(issuer_or_entity_id) do - service_providers[issuer_or_entity_id] - end - end - end - - private :update_saml_idp_config - - def get_saml_sp - if AccessToken.valid_token(params[:access_token]) - @sp = SamlServiceProvider.where(name: params[:name]).first - if @sp - render json: @sp, status: :ok - else - render json: {"error": "service provider with name #{params[:name]} not found"}, status: :not_found - end - else - render json: {"error": "Unauthorized user"}, status: :unauthorized - end - end - - def is_saml_enabled - if Figaro.env.ENABLE_SAML - return true - else - respond_to do |format| - format.html {render :file => "#{Rails.root}/public/saml_not_enabled", :layout => false, :status => :not_found} - format.xml {head :not_found} - format.any {head :not_found} - end - end - end - - private :is_saml_enabled -end diff --git a/app/models/organisation.rb b/app/models/organisation.rb new file mode 100644 index 00000000..4f20f142 --- /dev/null +++ b/app/models/organisation.rb @@ -0,0 +1,18 @@ +class Organisation < ActiveRecord::Base + validates :name, :url, :email_domain, presence: true + + def self.setup(attrs = {}) + attrs.stringify_keys! + attrs = attrs.select { |k, _v| %w(name url email_domain).include?(k) } + org = Organisation.new(attrs) + org.save if org.valid? + org + end + + def update_profile(attrs = {}) + attrs.stringify_keys! + attrs = attrs.select { |k, _v| %w(name url email_domain).include?(k) } + assign_attributes(attrs) + save if valid? + end +end diff --git a/app/models/saml_service_provider.rb b/app/models/saml_service_provider.rb deleted file mode 100644 index e17bd470..00000000 --- a/app/models/saml_service_provider.rb +++ /dev/null @@ -1,2 +0,0 @@ -class SamlServiceProvider < ActiveRecord::Base -end diff --git a/app/views/layouts/application.html.slim b/app/views/layouts/application.html.slim index 72273b1c..5c7db0b4 100755 --- a/app/views/layouts/application.html.slim +++ b/app/views/layouts/application.html.slim @@ -19,31 +19,32 @@ html lang="en" /! Fixed navbar nav.navbar.navbar-expand-md.navbar-dark.fixed-top.bg-dark a.navbar-brand href="/profile" gate - button.navbar-toggler aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label=("Toggle navigation") data-target="#navbarsExampleDefault" data-toggle="collapse" type="button" + button.navbar-toggler aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label=("Toggle navigation") data-target="#main-navigation" data-toggle="collapse" type="button" span.navbar-toggler-icon - #navbarsExampleDefault.collapse.navbar-collapse + #main-navigation.collapse.navbar-collapse ul.navbar-nav.mr-auto - li#user-index.nav-item - - if current_user.admin? - = link_to("Users", users_path, class: "nav-link") - li#group-index.nav-item - - if current_user.admin? || current_user.group_admin? - = link_to "Groups", groups_path, class: "nav-link" - li#hostmachine-index.nav-item - - if current_user.admin? - = link_to "Hosts", host_machines_path, class: "nav-link" + - if current_user.admin? + li#user-index.nav-item + = link_to("Users", users_path, class: "nav-link") + li#hostmachine-index.nav-item + = link_to "Hosts", host_machines_path, class: "nav-link" + li#organisation-index.nav-item + = link_to "Organisations", organisations_path, class: "nav-link" + - if current_user.admin? || current_user.group_admin? + li#group-index.nav-item + = link_to "Groups", groups_path, class: "nav-link" li#apiresource-index.nav-item = link_to "APIs", api_resources_path, class: "nav-link" li#vpn-index.nav-item = link_to "VPNs", vpns_path, class: "nav-link" li.nav-item.dropdown a#dropdown01.nav-link.dropdown-toggle aria-expanded="false" aria-haspopup="true" data-toggle="dropdown" href="http://example.com" New - .dropdown-menu aria-labelledby="dropdown01" + .dropdown-menu aria-labelledby="dropdown01" = link_to "API", new_api_resource_path, class: "dropdown-item" - - if current_user.admin? + - if current_user.admin? = link_to "Group", new_group_path, class: "dropdown-item" = link_to "VPN", new_vpn_path, class: "dropdown-item" - + = link_to "Organisation", new_organisation_path, class: "dropdown-item" ul.nav.navbar-nav.navbar-right li.nav-link = link_to "Sign out", users_sign_out_path,:method => :delete , class: "nav-link" diff --git a/app/views/organisations/_form.html.slim b/app/views/organisations/_form.html.slim new file mode 100644 index 00000000..2d4f0c03 --- /dev/null +++ b/app/views/organisations/_form.html.slim @@ -0,0 +1,16 @@ +- if flash.key?(:errors) + .alert.alert-danger#organisation_form_errors + b Issue creating application + br + - flash[:errors].each do |msg| + = "- #{msg}" + br +.form-group + = f.label :name + = f.text_field :name, class: 'form-control' +.form-group + = f.label :url + = f.text_field :url, class: 'form-control' +.form-group + = f.label :email_domain + = f.text_field :email_domain, class: 'form-control' diff --git a/app/views/organisations/index.html.slim b/app/views/organisations/index.html.slim new file mode 100644 index 00000000..0d6832a7 --- /dev/null +++ b/app/views/organisations/index.html.slim @@ -0,0 +1,26 @@ +.container.col-md-8 + .row.mb-3.mt-2 + .col-md-8 + h5 Organisations + .col-md-4.text-right + = link_to "New Organisation", new_organisation_path, class: "btn btn-primary", id: 'new_organisation_btn' + - if flash.key?(:success) + .alert.alert-success#organisation_form_success + = flash[:success] + #organisation_list.table-responsive + table.table.table-striped + thead + tr + th Name + th URL + th Email Domain + tbody + - if org_list.present? + - org_list.each do |org| + tr + td = link_to org.name, organisation_path(org) + td = link_to org.url, org.url + td = org.email_domain + - else + td.text-center colspan='3' + p There are no organisations yet, why don't you create an organisation diff --git a/app/views/organisations/new.html.slim b/app/views/organisations/new.html.slim new file mode 100644 index 00000000..88d6354b --- /dev/null +++ b/app/views/organisations/new.html.slim @@ -0,0 +1,8 @@ +.container.col-md-8 + .row.mb-3.mt-2 + .col-md-12 + h5 Create Organisation + hr + = form_for(org) do |f| + = render partial: 'form', locals: {f: f} + = f.submit 'Create Organisation', class: 'btn btn-primary mb-2' diff --git a/app/views/organisations/show.html.slim b/app/views/organisations/show.html.slim new file mode 100644 index 00000000..23a247b7 --- /dev/null +++ b/app/views/organisations/show.html.slim @@ -0,0 +1,8 @@ +.container.col-md-8 + .row.mb-3.mt-2 + .col-md-12 + h5 Update Organisation + hr + = form_for(org) do |f| + = render partial: 'form', locals: {f: f} + = f.submit 'Update Organisation', class: 'btn btn-primary mb-2' diff --git a/app/views/saml_idp/new.html.erb b/app/views/saml_idp/new.html.erb deleted file mode 100644 index 53bc9446..00000000 --- a/app/views/saml_idp/new.html.erb +++ /dev/null @@ -1,182 +0,0 @@ -<% if @saml_idp_fail_msg %> -
<%= @saml_idp_fail_msg %>
-<% end %> - - - - - - - Login - GATE – Single Sign on - - - - - - - - - - - - -
-
-
-
- GATE Single Sign-on Multifactor Authentication. -
-
- -
-
-
- -
-
- -
-
- - - <%= form_tag do %> - <%= hidden_field_tag("SAMLRequest", params[:SAMLRequest]) %> - <%= hidden_field_tag("RelayState", params[:RelayState]) %> - -

Enter your Username and Password

- -

- <%= label_tag :email %> - <%= text_field_tag :email, params[:email], :autocapitalize => "off", :autocorrect => "off", :autofocus => "autofocus", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %> -

- -

- <%= label_tag :password %> - <%= password_field_tag :password, params[:password], :autocapitalize => "off", :autocorrect => "off", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %> -

- -

- <%= submit_tag "Sign in", :class => "button big blueish" %> -

- <% end %> - - - -
-
- -
-
-
-
-
- - - - - diff --git a/config/initializers/saml_idp.rb b/config/initializers/saml_idp.rb deleted file mode 100755 index 85c0a48d..00000000 --- a/config/initializers/saml_idp.rb +++ /dev/null @@ -1,64 +0,0 @@ -return unless (Figaro.env.ENABLE_SAML && (defined?(Rails::Server) || defined?(Rails::Console))) - -SamlIdp.configure do |config| - base = Figaro.env.GATE_SERVER_URL - saml_base = "#{base}/saml" - - config.x509_certificate = Figaro.env.GATE_SAML_IDP_X509_CERTIFICATE.gsub("\\n", "\n") - config.secret_key = Figaro.env.GATE_SAML_IDP_SECRET_KEY.gsub("\\n", "\n") - - service_providers = {} - SamlServiceProvider.find_each do |sp| - service_providers[sp.sso_url] = { - :fingerprint => Figaro.env.GATE_SAML_IDP_FINGERPRINT, - :metadata_url => sp.metadata_url - } - end - - config.organization_name = Figaro.env.GATE_SAML_IDP_ORGANIZATION_NAME - config.organization_url = Figaro.env.GATE_SAML_IDP_ORGANIZATION_URL - - config.base_saml_location = saml_base - config.single_service_post_location = "#{saml_base}/auth" - config.session_expiry = Figaro.env.GATE_SAML_IDP_SESSION_EXPIRY.to_i - - config.name_id.formats = { - email_address: -> (principal) {principal.email}, - transient: -> (principal) {principal.user_login_id}, - persistent: -> (principal) {principal.user_login_id}, - name: -> (principal) {principal.name}, - } - - config.attributes = { - 'eduPersonPrincipalName' => { - 'name' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6', - 'name_format' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', - 'getter' => ->(principal) { - "#{principal.email}" - } - }, - } - - config.service_provider.metadata_persister = ->(identifier, settings) { - fname = identifier.to_s.gsub(/\/|:/, '_') - `mkdir -p #{Rails.root.join('cache/saml/metadata')}` - File.open Rails.root.join("cache/saml/metadata/#{fname}"), 'r+b' do |f| - Marshal.dump settings.to_h, f - end - } - - config.service_provider.persisted_metadata_getter = ->(identifier, _service_provider) { - fname = identifier.to_s.gsub(/\/|:/, '_') - `mkdir -p #{Rails.root.join('cache/saml/metadata')}` - full_filename = Rails.root.join("cache/saml/metadata/#{fname}") - if File.file?(full_filename) - File.open full_filename, 'rb' do |f| - Marshal.load f - end - end - } - - config.service_provider.finder = ->(issuer_or_entity_id) do - service_providers[issuer_or_entity_id] - end -end diff --git a/config/routes.rb b/config/routes.rb index b3b12e27..4c1369d9 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,10 @@ devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }, :path_names => { :sign_in => 'login', :sign_out => 'logout' } devise_scope :user do + authenticated :user do + resources :organisations, except: %i(destroy) + end + delete "/users/sign_out" => "devise/sessions#destroy" match 'download_vpn', to: 'profile#download_vpn', via: :get, format: :html match 'download_vpn_for_ios_and_mac', to: 'profile#download_vpn_for_ios_and_mac', via: :get, format: :html diff --git a/coverage/.last_run.json b/coverage/.last_run.json index 113c8cbe..bd441664 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,5 +1,5 @@ { "result": { - "covered_percent": 74.74 + "covered_percent": 76.92 } } diff --git a/coverage/.resultset.json b/coverage/.resultset.json index b26cffbc..fc58d173 100644 --- a/coverage/.resultset.json +++ b/coverage/.resultset.json @@ -15,9 +15,6 @@ null, 1, 1, - 0, - 0, - null, null, 1, 0, @@ -798,7 +795,7 @@ 1, null, 1, - 0, + 1, null, null, 1, @@ -1293,7 +1290,7 @@ 1, null, 1, - 2, + 5, 1, 1, null, @@ -1591,163 +1588,6 @@ null, null ], - "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/controllers/saml_idp_controller_spec.rb": [ - 1, - null, - 1, - null, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - null, - 1, - 1, - 1, - null, - 1, - null, - 1, - null, - 1, - 1, - 1, - 1, - null, - null, - 1, - 1, - 2, - 2, - 2, - 2, - null, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - null, - 1, - 1, - null, - 1, - 1, - 1, - 1, - 1, - 1, - null, - null, - null, - null - ], - "/Users/siddarthramaswamy/GoJek/Sites/gate/app/controllers/saml_idp_controller.rb": [ - 1, - 1, - 1, - null, - 1, - 1, - 1, - null, - 0, - 0, - 0, - 0, - null, - null, - null, - null, - 1, - 0, - 0, - 0, - 0, - null, - 0, - 0, - 0, - null, - null, - 0, - null, - null, - 1, - 0, - 0, - null, - 0, - null, - null, - 1, - null, - 1, - 0, - null, - null, - 1, - null, - 1, - 1, - 1, - 1, - 1, - null, - 0, - null, - null, - null, - 1, - 1, - 1, - 1, - 1, - null, - null, - null, - null, - 1, - 0, - null, - null, - null, - null, - 1, - null, - 1, - 1, - 1, - 1, - 1, - null, - 0, - null, - null, - 0, - null, - null, - null, - 1, - 1, - 1, - null, - 0, - 0, - 0, - 0, - null, - null, - null, - null, - 1, - null - ], "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/controllers/users_controller_spec.rb": [ 1, null, @@ -2199,6 +2039,161 @@ null, null ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/features/layout_spec.rb": [ + 1, + 1, + 2, + 2, + 2, + 1, + 1, + 1, + 1, + null, + null, + null, + null, + 1, + 3, + null, + null, + null, + null, + 1, + 1, + 1, + 1, + null, + null, + null, + null, + null, + 1, + 4, + null, + null, + null, + null, + 1, + 1, + 1, + 1, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + 1, + 10, + null, + null, + null, + null, + null + ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/features/organisations/create_spec.rb": [ + 1, + 1, + 3, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + null + ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/features/organisations/list_spec.rb": [ + 1, + 1, + 4, + 4, + 1, + 1, + 1, + 1, + null, + 1, + 1, + 1, + 1, + 1, + 5, + null, + null, + 5, + null, + null, + 5, + null, + null, + null, + null, + 1, + 1, + 1, + 1, + 1, + 5, + null, + null, + null, + null, + null + ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/features/organisations/update_spec.rb": [ + 1, + 1, + 3, + 2, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + null + ], "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/lib/tasks/users_rake_spec.rb": [ 1, null, @@ -2262,14 +2257,14 @@ 1, null, 1, - 21, - 21, + 19, + 19, null, null, 1, null, 1, - 29, + 27, null, null ], @@ -2455,12 +2450,12 @@ null, null, 1, - 190, + 198, null, null, 1, - 190, - 190, + 198, + 198, null, null, 1, @@ -2751,6 +2746,69 @@ 1, null ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/models/organisation_spec.rb": [ + 1, + null, + 1, + 1, + 3, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + null, + 1, + 3, + 2, + 1, + 1, + 1, + 1, + 1, + 1, + null, + null, + 1, + 1, + 1, + 1, + null, + null, + null + ], + "/Users/siddarthramaswamy/GoJek/Sites/gate/app/models/organisation.rb": [ + 1, + 1, + null, + 1, + 4, + 14, + 4, + 4, + 4, + null, + null, + 1, + 4, + 14, + 4, + 4, + null, + null + ], "/Users/siddarthramaswamy/GoJek/Sites/gate/spec/models/user_spec.rb": [ 1, 1, @@ -3329,10 +3387,6 @@ 1, null ], - "/Users/siddarthramaswamy/GoJek/Sites/gate/app/models/saml_service_provider.rb": [ - 1, - null - ], "/Users/siddarthramaswamy/GoJek/Sites/gate/app/models/vpn_group_association.rb": [ 1, 1, @@ -3356,35 +3410,69 @@ 1, null ], - "/Users/siddarthramaswamy/GoJek/Sites/gate/lib/tasks/app.rake": [ + "/Users/siddarthramaswamy/GoJek/Sites/gate/app/controllers/organisations_controller.rb": [ 1, 1, + 5, + null, null, 1, - 0, - 0, + 3, null, null, 1, - 0, - 0, - 0, - 0, + 2, + 2, + 1, + 1, + null, + 1, + 1, + null, + null, + null, + 1, + 2, + 2, + 2, + 1, + 1, + null, + 1, + 1, + null, + null, + null, + 1, + 3, + null, + null, + 1, + null, + 1, + 5, + 5, + 5, + null, + null, + 1, + 4, null, null ], - "/Users/siddarthramaswamy/GoJek/Sites/gate/lib/tasks/saml.rake": [ + "/Users/siddarthramaswamy/GoJek/Sites/gate/lib/tasks/app.rake": [ 1, 1, null, 1, 0, 0, + null, + null, + 1, 0, 0, 0, - null, - null, 0, null, null @@ -3563,6 +3651,6 @@ null ] }, - "timestamp": 1528871271 + "timestamp": 1528908734 } } diff --git a/db/migrate/20180613074108_create_organisations.rb b/db/migrate/20180613074108_create_organisations.rb new file mode 100644 index 00000000..41adef64 --- /dev/null +++ b/db/migrate/20180613074108_create_organisations.rb @@ -0,0 +1,11 @@ +class CreateOrganisations < ActiveRecord::Migration + def change + create_table :organisations do |t| + t.string :name + t.string :url + t.string :email_domain + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20180613165050_drop_saml_service_providers.rb b/db/migrate/20180613165050_drop_saml_service_providers.rb new file mode 100644 index 00000000..b432f844 --- /dev/null +++ b/db/migrate/20180613165050_drop_saml_service_providers.rb @@ -0,0 +1,5 @@ +class DropSamlServiceProviders < ActiveRecord::Migration + def change + drop_table :saml_service_providers + end +end diff --git a/db/schema.rb b/db/schema.rb index 1829adca..33dbc5bc 100755 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180318083000) do +ActiveRecord::Schema.define(version: 20180613165050) do create_table "access_tokens", force: :cascade do |t| t.string "hashed_token", limit: 255 @@ -113,10 +113,10 @@ add_index "ip_addresses", ["host_machine_id"], name: "index_ip_addresses_on_host_machine_id", using: :btree add_index "ip_addresses", ["mac_address"], name: "index_ip_addresses_on_mac_address", using: :btree - create_table "saml_service_providers", force: :cascade do |t| - t.string "name", limit: 255, null: false - t.string "sso_url", limit: 255, null: false - t.string "metadata_url", limit: 255, null: false + create_table "organisations", force: :cascade do |t| + t.string "name", limit: 255 + t.string "url", limit: 255 + t.string "email_domain", limit: 255 t.datetime "created_at", null: false t.datetime "updated_at", null: false end diff --git a/lib/tasks/saml.rake b/lib/tasks/saml.rake deleted file mode 100644 index 619e3865..00000000 --- a/lib/tasks/saml.rake +++ /dev/null @@ -1,14 +0,0 @@ -namespace :saml do - desc "Common SAML tasks" - - task :cert do - if Figaro.env.GATE_SAML_IDP_X509_CERTIFICATE.blank? - puts "[WARN] Certificate for SAML is not available." - puts "[WARN] Please add it in env file with key name GATE_SAML_IDP_X509_CERTIFICATE." - puts "[WARN] And then re-run your server." - exit -1 - end - - puts Figaro.env.GATE_SAML_IDP_X509_CERTIFICATE.gsub("\\n", "\n").tr('"', '') - end -end diff --git a/public/saml_not_enabled.html b/public/saml_not_enabled.html deleted file mode 100644 index 73dd9e22..00000000 --- a/public/saml_not_enabled.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - The page you were looking for doesn't exist (404) - - - - - -
-
-

It looks like SAML IDP is not enabled on this server.

-

Please check with your administrator to enable saml.

-
-

If you are the application owner check the logs for more information.

-
- - diff --git a/spec/controllers/saml_idp_controller_spec.rb b/spec/controllers/saml_idp_controller_spec.rb deleted file mode 100755 index 088130e2..00000000 --- a/spec/controllers/saml_idp_controller_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'rails_helper' - -RSpec.describe SamlIdpController, type: :controller do - - it "should return proper xml for admin user" do - cert_helper = CertificateHelper.new - SamlIdp.configure do |config| - config.x509_certificate = cert_helper.get_cert - config.secret_key = cert_helper.get_private_key - config.organization_name = "Test" - config.organization_url = "test-example.com" - end - FactoryBot.create(:group) - user = FactoryBot.create(:user, name: "foobar", user_login_id: "foobar", email: "foobar@foobar.com", admin: 1) - sign_in user - - allow(Figaro.env).to receive(:ENABLE_SAML).and_return(true) - - get :show - - hash = Hash.from_xml(response.body) - expect(hash["EntityDescriptor"]["Organization"]["OrganizationName"]).to eq("Test") - expect(hash["EntityDescriptor"]["Organization"]["OrganizationDisplayName"]).to eq("Test") - expect(hash["EntityDescriptor"]["Organization"]["OrganizationURL"]).to eq("test-example.com") - end - - describe "Service provider" do - before(:each) do - @user = build(:user) - @user.access_token = build(:access_token) - @user.save - @token = @user.access_token.token - end - it "should create new service provider in db" do - post :add_saml_sp, name: "test_sp", sso_url: "sso1", metadata_url: "metadata1", access_token: @token - body = JSON.parse(response.body) - expect(response.status).to eq(200) - expect(body['name']).to eq("test_sp") - expect(body['sso_url']).to eq("sso1") - expect(body['metadata_url']).to eq("metadata1") - end - it "should create new service provider in db" do - FactoryBot.create(:saml_service_provider, name: "test_sp", sso_url: "sso1", metadata_url: "metadata1") - - get :get_saml_sp, name: "test_sp", access_token: @token - body = JSON.parse(response.body) - expect(response.status).to eq(200) - expect(body['name']).to eq("test_sp") - expect(body['sso_url']).to eq("sso1") - expect(body['metadata_url']).to eq("metadata1") - end - end - -end diff --git a/spec/factories/organisations.rb b/spec/factories/organisations.rb new file mode 100644 index 00000000..8610cd98 --- /dev/null +++ b/spec/factories/organisations.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :organisation do + name Faker::Company.name + url Faker::Internet.url + email_domain Faker::Internet.email.split('@').last + end +end diff --git a/spec/factories/saml_service_providers.rb b/spec/factories/saml_service_providers.rb deleted file mode 100644 index d0c49a45..00000000 --- a/spec/factories/saml_service_providers.rb +++ /dev/null @@ -1,5 +0,0 @@ -FactoryBot.define do - factory :saml_service_provider do - - end -end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 49771c04..7326c085 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -5,7 +5,37 @@ sequence(:email) {|n| "test#{n}@test.com"} active true admin false - encrypted_password "" + sequence(:reset_password_token) {|n| "secret#{n}" } + after(:create) do |user, evaluator| + group = Group.first + user.groups << group unless group.blank? + group = Group.create(name: user.user_login_id) + user.groups << group + user.save! + end + end + factory :group_admin, class: User do + sequence(:name){|n| "TestUser#{n}}"} + sequence(:user_login_id){|n| "test#{n}}"} + sequence(:email) {|n| "test#{n}@test.com"} + active true + admin false + sequence(:reset_password_token) {|n| "secret#{n}" } + after(:create) do |user, evaluator| + group = Group.first + user.groups << group unless group.blank? + group = Group.create(name: user.user_login_id) + user.groups << group + user.save! + GroupAdmin.create(user: user, group: group) + end + end + factory :admin_user, class: User do + sequence(:name){|n| "TestUser#{n}}"} + sequence(:user_login_id){|n| "test#{n}}"} + sequence(:email) {|n| "test#{n}@test.com"} + active true + admin true sequence(:reset_password_token) {|n| "secret#{n}" } after(:create) do |user, evaluator| group = Group.first diff --git a/spec/features/layout_spec.rb b/spec/features/layout_spec.rb new file mode 100644 index 00000000..0ea183b6 --- /dev/null +++ b/spec/features/layout_spec.rb @@ -0,0 +1,56 @@ +require 'rails_helper' +RSpec.feature 'Layout', type: :feature do + let(:user) { create(:user) } + let(:group_admin) { create(:group_admin) } + let(:admin) { create(:admin_user) } + scenario 'Access to user links' do + sign_in(user) + visit profile_path + links = { + 'APIs' => api_resources_path, + 'VPNs' => vpns_path, + 'API' => new_api_resource_path, + } + links.each do |link_text, link_href| + expect(page).to have_xpath( + "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" + ) + end + end + scenario 'Access to group admin links' do + sign_in(group_admin) + visit profile_path + links = { + 'APIs' => api_resources_path, + 'Groups' => groups_path, + 'VPNs' => vpns_path, + 'API' => new_api_resource_path, + } + links.each do |link_text, link_href| + expect(page).to have_xpath( + "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" + ) + end + end + scenario 'Access to admin links' do + sign_in(admin) + visit root_path + links = { + 'Users' => users_path, + 'Hosts' => host_machines_path, + 'Organisations' => organisations_path, + 'Groups' => groups_path, + 'APIs' => api_resources_path, + 'VPNs' => vpns_path, + 'API' => new_api_resource_path, + 'Group' => new_group_path, + 'VPN' => new_vpn_path, + 'Organisation' => new_organisation_path, + } + links.each do |link_text, link_href| + expect(page).to have_xpath( + "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" + ) + end + end +end diff --git a/spec/features/organisations/create_spec.rb b/spec/features/organisations/create_spec.rb new file mode 100644 index 00000000..8bebd648 --- /dev/null +++ b/spec/features/organisations/create_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' +RSpec.feature 'Create Organisation', type: :feature do + let(:org_data) { attributes_for(:organisation) } + let(:user) { create(:user) } + scenario 'Create an organisation successfully' do + sign_in(user) + visit new_organisation_path + fill_in 'organisation_name', with: org_data[:name] + fill_in 'organisation_url', with: org_data[:url] + fill_in 'organisation_email_domain', with: org_data[:email_domain] + click_button('Create Organisation') + expect(current_path).to eq(organisations_path) + expect(page).to have_xpath( + "//div[@id='organisation_form_success' and .='Successfully created organisation']" + ) + end + scenario 'Display Errors on Creating Organisation' do + sign_in(user) + visit new_organisation_path + fill_in 'organisation_name', with: org_data[:name] + click_button('Create Organisation') + expect(current_path).to eq(new_organisation_path) + expect(page).to have_xpath( + "//div[@id='organisation_form_errors']" + ) + end +end diff --git a/spec/features/organisations/list_spec.rb b/spec/features/organisations/list_spec.rb new file mode 100644 index 00000000..ed0aa8b7 --- /dev/null +++ b/spec/features/organisations/list_spec.rb @@ -0,0 +1,36 @@ +require 'rails_helper' +RSpec.feature 'List Organisations', type: :feature do + let!(:orgs) { create_list(:organisation, 5) } + let(:user) { create(:user) } + scenario 'Can create an organisation' do + sign_in(user) + visit organisations_path + expect(page).to have_xpath("//a[@id='new_organisation_btn']") + end + scenario 'View list of organisations' do + sign_in(user) + visit organisations_path + table_xpath = "//div[@id='organisation_list']/table" + orgs.each do |org| + expect(page).to have_xpath( + "#{table_xpath}//td/a[@href='#{organisation_path(org)}' and .='#{org.name}']" + ) + expect(page).to have_xpath( + "#{table_xpath}//td/a[@href='#{org.url}' and .='#{org.url}']" + ) + expect(page).to have_xpath( + "#{table_xpath}//td[.='#{org.email_domain}']" + ) + end + end + scenario 'Ability to see organsiation details' do + sign_in(user) + visit organisations_path + table_xpath = "//div[@id='organisation_list']/table" + orgs.each do |org| + expect(page).to have_xpath( + "#{table_xpath}//td/a[@href='#{organisation_path(org)}' and .='#{org.name}']" + ) + end + end +end diff --git a/spec/features/organisations/update_spec.rb b/spec/features/organisations/update_spec.rb new file mode 100644 index 00000000..dac5cc7d --- /dev/null +++ b/spec/features/organisations/update_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' +RSpec.feature 'Update Organisation', type: :feature do + let!(:org) { create(:organisation) } + let(:org_data) { attributes_for(:organisation) } + let(:user) { create(:user) } + scenario 'Create an organisation successfully' do + sign_in(user) + visit organisation_path(org) + fill_in 'organisation_name', with: org_data[:name] + fill_in 'organisation_url', with: org_data[:url] + fill_in 'organisation_email_domain', with: org[:email_domain] + click_button('Update Organisation') + expect(current_path).to eq(organisations_path) + expect(page).to have_xpath( + "//div[@id='organisation_form_success' and .='Successfully updated organisation']" + ) + end + scenario 'Display Errors on Creating Organisation' do + sign_in(user) + visit organisation_path(org) + fill_in 'organisation_name', with: '' + click_button('Update Organisation') + expect(current_path).to eq(organisation_path(org)) + expect(page).to have_xpath( + "//div[@id='organisation_form_errors']" + ) + end +end diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb new file mode 100644 index 00000000..495eeabc --- /dev/null +++ b/spec/models/organisation_spec.rb @@ -0,0 +1,41 @@ +require 'rails_helper' + +RSpec.describe Organisation, type: :model do + describe '.setup' do + let(:org_data) { attributes_for(:organisation) } + it 'should create organisation' do + org = Organisation.setup(org_data) + expect(org.persisted?).to eq(true) + expect(org.valid?).to eq(true) + expect(org.name).to eq(org_data['name']) + expect(org.url).to eq(org_data['url']) + expect(org.email_domain).to eq(org_data['email_domain']) + end + + it 'should not create organisation if validations fail' do + org = Organisation.setup(name: org_data[:name]) + expect(org.persisted?).to eq(false) + expect(org.valid?).to eq(false) + expect(org.errors.messages.key?(:url)).to eq(true) + expect(org.errors.messages.key?(:email_domain)).to eq(true) + end + end + + describe '.update_profile' do + let(:org) { create(:organisation) } + let(:org_data) { attributes_for(:organisation) } + it 'should update organisation profile' do + org.update_profile(org_data) + expect(org.valid?).to eq(true) + expect(org.name).to eq(org_data['name']) + expect(org.url).to eq(org_data['url']) + expect(org.email_domain).to eq(org_data['email_domain']) + end + + it 'shouldn not update organisation profile if validations fail' do + org.update_profile(name: '') + expect(org.valid?).to eq(false) + expect(org.errors.messages.key?(:name)).to eq(true) + end + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index e62f2368..67b71ca3 100755 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -6,7 +6,6 @@ require 'spec_helper' require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! -require 'support/controller_helpers' require 'helpers/factory_girl' require 'helpers/x509_certificate_helper' require 'webmock/rspec' @@ -15,6 +14,7 @@ require 'simplecov' require 'simplecov-console' require 'pry' +require 'capybara/rspec' # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are @@ -38,33 +38,13 @@ RSpec.configure do |config| config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::ControllerHelpers, type: :view - config.include ControllerHelpers, type: :controller + config.include Devise::Test::IntegrationHelpers, type: :feature + #config.include Warden::Test::Helpers config.render_views = true - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" - - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. config.use_transactional_fixtures = true - - # RSpec Rails can automatically mix in different behaviours to your tests - # based on their file location, for example enabling you to call `get` and - # `post` in specs under `spec/controllers`. - # - # You can disable this behaviour by removing the line below, and instead - # explicitly tag your specs with their type, e.g.: - # - # RSpec.describe UsersController, :type => :controller do - # # ... - # end - # - # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs - config.infer_spec_type_from_file_location! - # Filter lines from Rails gems in backtraces. - config.filter_rails_from_backtrace! + #config.filter_rails_from_backtrace! # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") # rspec-expectations config goes here. You can use an alternate diff --git a/spec/support/controller_helpers.rb b/spec/support/controller_helpers.rb deleted file mode 100644 index 39619974..00000000 --- a/spec/support/controller_helpers.rb +++ /dev/null @@ -1,3 +0,0 @@ -module ControllerHelpers - -end