├── .deepsource.toml ├── .dockerignore ├── .env.example ├── .gitignore ├── .rspec ├── .rubocop.yml ├── .ruby-version ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── Rakefile ├── VERSION ├── api_blueprint ├── bin │ └── dredd_server.sh ├── group.apib ├── hooks │ └── dredd_hooks.rb ├── user.apib └── vpns.apib ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── .keep │ │ ├── app_store_en_badge.png │ │ ├── apple-touch-icon-114x114-precomposed.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120-precomposed.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144-precomposed.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152-precomposed.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-180x180-precomposed.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57-precomposed.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-72x72-precomposed.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76-precomposed.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── bg.jpg │ │ ├── favicon.ico │ │ ├── google_play_en_badge.png │ │ ├── logo.png │ │ ├── saml_configure_datadog_01.png │ │ ├── saml_configure_datadog_02.png │ │ ├── saml_configure_datadog_03.png │ │ ├── saml_configure_datadog_04.png │ │ ├── saml_configure_datadog_05.png │ │ ├── saml_configure_datadog_06.png │ │ ├── saml_configure_datadog_07.png │ │ ├── saml_configure_datadog_08.png │ │ └── saml_configure_datadog_09.png │ ├── javascripts │ │ ├── admin.coffee │ │ ├── api_resources.coffee │ │ ├── application.js │ │ ├── bootstrap.js.coffee │ │ ├── group.coffee │ │ ├── groups.coffee │ │ ├── home.coffee │ │ ├── host_access_groups.coffee │ │ ├── host_machine_groups.coffee │ │ ├── host_machines.coffee │ │ ├── nss.coffee │ │ ├── omniauth_callbacks.coffee │ │ ├── profile.coffee │ │ ├── users.coffee │ │ ├── utilities.coffee │ │ └── viewport.js │ └── stylesheets │ │ ├── application.scss │ │ ├── bootstrap-social.scss │ │ ├── general.css │ │ ├── home.scss.erb │ │ ├── profile.css │ │ └── scaffolds.scss ├── clients │ └── data_dog_client.rb ├── controllers │ ├── admin_controller.rb │ ├── api │ │ └── v1 │ │ │ ├── base_controller.rb │ │ │ ├── endpoints_controller.rb │ │ │ ├── groups_controller.rb │ │ │ ├── users_controller.rb │ │ │ └── vpns_controller.rb │ ├── api_resources_controller.rb │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── groups_controller.rb │ ├── home_controller.rb │ ├── host_controller.rb │ ├── host_machine_groups_controller.rb │ ├── host_machines_controller.rb │ ├── nss_controller.rb │ ├── organisations_controller.rb │ ├── pings_controller.rb │ ├── profile_controller.rb │ ├── saml_idp_controller.rb │ ├── users │ │ ├── auth_controller.rb │ │ └── omniauth_callbacks_controller.rb │ ├── users_controller.rb │ ├── vpn_domain_name_servers_controller.rb │ └── vpns_controller.rb ├── helpers │ ├── admin_helper.rb │ ├── api_resources_helper.rb │ ├── application_helper.rb │ ├── group_helper.rb │ ├── groups_helper.rb │ ├── home_helper.rb │ ├── host_access_groups_helper.rb │ ├── host_machine_groups_helper.rb │ ├── host_machines_helper.rb │ ├── nss_helper.rb │ ├── omniauth_callbacks_helper.rb │ ├── profile_helper.rb │ └── users_helper.rb ├── lib │ ├── datadog.rb │ └── saml_app.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── access_token.rb │ ├── api_resource.rb │ ├── application_record.rb │ ├── concerns │ │ ├── .keep │ │ └── ms_chap_auth.rb │ ├── endpoint.rb │ ├── group.rb │ ├── group_admin.rb │ ├── group_association.rb │ ├── group_endpoint.rb │ ├── host.rb │ ├── host_access_group.rb │ ├── host_machine.rb │ ├── ip_address.rb │ ├── organisation.rb │ ├── saml_app_config.rb │ ├── user.rb │ ├── vpn.rb │ ├── vpn_domain_name_server.rb │ ├── vpn_group_association.rb │ ├── vpn_group_user_association.rb │ ├── vpn_search_domain.rb │ └── vpn_supplemental_match_domain.rb ├── validators │ └── email_validator.rb └── views │ ├── admin │ └── index.html.slim │ ├── api │ └── v1 │ │ └── users │ │ └── show.json.jbuilder │ ├── api_resources │ ├── _api_resource.json.jbuilder │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── index.json.jbuilder │ ├── new.html.slim │ ├── show.html.slim │ └── show.json.jbuilder │ ├── application │ ├── _admin.html.slim │ ├── _groups_header.html.slim │ └── _host_header.html.slim │ ├── common │ └── errors.json.jbuilder │ ├── groups │ ├── _form.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── home │ └── index.html.slim │ ├── host_machines │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim │ ├── layouts │ ├── application.html.slim │ ├── home.html.slim │ └── profile.html.slim.disabled │ ├── nss │ └── add_host.json.jbuilder │ ├── organisations │ ├── _form.html.slim │ ├── config_saml_app.html.slim │ ├── index.html.slim │ ├── new.html.slim │ ├── saml_apps │ │ └── _datadog.html.erb │ └── show.html.slim │ ├── profile │ ├── _group_search.html.slim │ ├── _user_search.html.slim │ ├── group_admin.html.slim │ ├── list.html.slim │ ├── public_key.html.slim │ ├── show.html.slim │ ├── user.html.slim │ └── user_admin.html.slim │ ├── saml_idp │ └── idp │ │ └── new.html.erb │ ├── users │ ├── _search.html.slim │ ├── index.html.slim │ ├── new.html.erb │ └── show.html.slim │ └── vpns │ ├── _form.html.slim │ ├── edit.html.slim │ ├── index.html.slim │ ├── new.html.slim │ └── show.html.slim ├── bin ├── bundle ├── rails ├── rake ├── setup └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── integration.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── dotenv.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── new_framework_defaults.rb │ ├── new_framework_defaults_7_0.rb │ ├── permissions_policy.rb │ ├── session_store.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.bootstrap.yml │ └── en.yml ├── newrelic.yml ├── puma.rb ├── redis.yml ├── routes.rb ├── schedule.rb ├── secrets.yml ├── spring.rb └── storage.yml ├── db ├── migrate │ ├── 20160419122430_devise_create_users.rb │ ├── 20160419132647_add_provider_to_users.rb │ ├── 20160419144739_add_name_to_users.rb │ ├── 20160427123146_add_auth_key_to_user.rb │ ├── 20160427123233_add_provisioning_uri_to_user.rb │ ├── 20160519042340_add_active_to_users.rb │ ├── 20160519064340_add_default_value_to_users.rb │ ├── 20160615044834_create_hosts.rb │ ├── 20160615045052_add_admin_to_user.rb │ ├── 20160615112805_add_user_to_host.rb │ ├── 20160628140022_add_deleted_at_to_host.rb │ ├── 20160628140440_add_deleted_by_to_host.rb │ ├── 20160629043358_add_homedir_to_user.rb │ ├── 20160629043415_add_shell_to_user.rb │ ├── 20160629075435_create_groups.rb │ ├── 20160701090045_create_group_associations.rb │ ├── 20160701112600_add_deleted_properties_to_group.rb │ ├── 20160707115313_create_access_tokens.rb │ ├── 20160714115228_add_public_key_to_user.rb │ ├── 20160908081651_create_host_machines.rb │ ├── 20161003145832_create_host_access_groups.rb │ ├── 20170803140620_add_user_login_id_to_user.rb │ ├── 20171013115441_create_versions.rb │ ├── 20171016064705_remove_index_group_name.rb │ ├── 20171016071526_add_unique_index_on_groups_name.rb │ ├── 20171031060034_create_group_admin.rb │ ├── 20171031060217_add_foreign_key_ref_on_group_admin.rb │ ├── 20171031100758_create_vpns.rb │ ├── 20171031101026_create_vpn_group_association.rb │ ├── 20171031103518_add_foreign_key_ref_on_vpn_group_association.rb │ ├── 20171031113123_create_vpn_group_user_association.rb │ ├── 20171031121702_add_foreign_key_ref_on_vpn_group_user_association.rb │ ├── 20171102071909_add_ip_address_to_vpns.rb │ ├── 20171107114249_remove_url_from_vpns.rb │ ├── 20171108130234_add_user_id_to_access_token.rb │ ├── 20171108130353_add_foreign_key_ref_on_access_tokens.rb │ ├── 20171124090240_add_uuid_to_vpns.rb │ ├── 20171124114427_create_vpn_domain_name_servers.rb │ ├── 20171124114830_create_vpn_search_domains.rb │ ├── 20171124115925_create_vpn_supplemental_match_domains.rb │ ├── 20180104081814_add_product_name_to_users.rb │ ├── 20180202102206_create_saml_service_providers.rb │ ├── 20180214050204_add_api_key_to_host_machines.rb │ ├── 20180214052451_create_ip_addresses.rb │ ├── 20180214052644_add_host_machine_to_ip_address.rb │ ├── 20180219150818_add_description_to_group.rb │ ├── 20180222135930_add_access_key_to_host_machine.rb │ ├── 20180222140000_add_access_key_to_user.rb │ ├── 20180227051732_create_api_resources.rb │ ├── 20180301010021_add_user_to_api_resources.rb │ ├── 20180301010035_add_group_to_api_resources.rb │ ├── 20180306231200_add_deactivated_at_to_users.rb │ ├── 20180311082600_rename_access_key_in_api_resources.rb │ ├── 20180311161200_rename_token_in_access_tokens.rb │ ├── 20180318083000_create_indexes_to_speedup_nss_controller.rb │ ├── 20180613074108_create_organisations.rb │ ├── 20180613165050_drop_saml_service_providers.rb │ ├── 20180723175600_update_organisations_for_saml.rb │ ├── 20181002023107_add_default_admins_to_host_machines.rb │ ├── 20181016093315_create_saml_app_configs.rb │ ├── 20181208184236_add_fields_to_user.rb │ ├── 20190624024930_add_expiration_date_to_group_associations.rb │ ├── 20190820070910_create_endpoints.rb │ ├── 20190820075040_create_group_endpoints.rb │ ├── 20190820080624_add_foreign_key_ref_on_group_endpoints.rb │ ├── 20200113065717_add_sessions_table.rb │ ├── 20220926001848_add_service_name_to_active_storage_blobs.active_storage.rb │ ├── 20220926001849_create_active_storage_variant_records.active_storage.rb │ └── 20220926001850_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb ├── schema.rb ├── seeds.rb └── seeds │ ├── development.rb │ ├── production.rb │ └── test.rb ├── docker-compose.yaml ├── docs ├── additional_setup.md ├── administration.md ├── dredd_setup.md ├── newrelic.md └── oauth_setup.md ├── dredd.yml ├── lib ├── assets │ └── .keep ├── tasks │ ├── .keep │ ├── app.rake │ ├── setup.rake │ ├── users.rake │ └── vpn.rake └── vpn │ ├── mobileconfig.erb │ ├── mobileconfig.rb │ └── namespace.rb ├── node_modules └── .yarn-integrity ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── scripts ├── gen-client-conf └── gen-client-keys ├── setup.sh ├── spec ├── clients │ └── data_dog_client_spec.rb ├── controllers │ ├── admin_controller_spec.rb │ ├── api │ │ └── v1 │ │ │ ├── api_controller_spec.rb │ │ │ ├── endpoints_controller_spec.rb │ │ │ ├── groups_controller_spec.rb │ │ │ ├── users_controller_spec.rb │ │ │ └── vpns_controller_spec.rb │ ├── api_resources_controller_spec.rb │ ├── groups_controller_spec.rb │ ├── home_controller_spec.rb │ ├── host_machine_groups_controller_spec.rb │ ├── host_machines_controller_spec.rb │ ├── nss_controller_spec.rb │ ├── omniauth_callbacks_controller_spec.rb │ ├── organisations_controller_spec.rb │ ├── profile_controller_spec.rb │ ├── users │ │ └── auth_controller_spec.rb │ ├── users_controller_spec.rb │ └── vpns_controller_spec.rb ├── factories │ ├── access_tokens.rb │ ├── api_resources.rb │ ├── endpoints.rb │ ├── group_associations.rb │ ├── groups.rb │ ├── host_access_groups.rb │ ├── host_machine_groups.rb │ ├── host_machines.rb │ ├── ip_addresses.rb │ ├── organisations.rb │ ├── saml_app_configs.rb │ ├── user_host_access_groups.rb │ ├── users.rb │ └── vpns.rb ├── features │ ├── layout_spec.rb │ ├── organisations │ │ ├── add_user_saml_app_spec.rb │ │ ├── config_saml_app_spec.rb │ │ ├── create_spec.rb │ │ ├── list_spec.rb │ │ ├── list_user_saml_app_spec.rb │ │ ├── remove_user_saml_app_spec.rb │ │ ├── save_config_saml_app_spec.rb │ │ ├── setup_saml_spec.rb │ │ └── update_spec.rb │ ├── saml │ │ └── show_spec.rb │ └── users │ │ ├── create_user_spec.rb │ │ └── regenerate_auth_spec.rb ├── helpers │ └── application_helper_spec.rb ├── lib │ ├── datadog_spec.rb │ ├── saml_app_spec.rb │ └── tasks │ │ └── users_rake_spec.rb ├── models │ ├── access_token_spec.rb │ ├── api_resource_spec.rb │ ├── endpoint_spec.rb │ ├── group_association_spec.rb │ ├── group_endpoint_spec.rb │ ├── group_spec.rb │ ├── host_machine_spec.rb │ ├── host_spec.rb │ ├── ip_address_spec.rb │ ├── organisation_spec.rb │ ├── user_spec.rb │ └── vpn_spec.rb ├── rails_helper.rb ├── routing │ └── api_resources_routing_spec.rb ├── spec_helper.rb ├── support │ └── helpers │ │ └── x509_certificate_helper.rb └── views │ ├── api_resources │ ├── edit.html.slim_spec.rb │ ├── index.html.slim_spec.rb │ ├── new.html.slim_spec.rb │ └── show.html.slim_spec.rb │ ├── groups │ └── show.html.slim_spec.rb │ └── layouts │ └── home.html.slim_spec.rb ├── vendor └── assets │ ├── javascripts │ └── .keep │ └── stylesheets │ └── .keep └── yarn.lock /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "ruby" 5 | enabled = true 6 | 7 | [[analyzers]] 8 | name = "javascript" 9 | enabled = true 10 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /log/* 2 | !/log/.keep 3 | /tmp 4 | .idea 5 | .env 6 | *.swp 7 | config/application.yml 8 | dump.rdb 9 | coverage 10 | .git 11 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | GATE_SERVER_URL=http://localhost:3000 2 | SIGN_IN_TYPE= 3 | GATE_OAUTH_CLIENT_ID=totally_secret_client_id 4 | GATE_OAUTH_CLIENT_SECRET=totally_secret 5 | GATE_HOSTED_DOMAIN=gate.domain 6 | GATE_HOSTED_DOMAINS=test1.com,test2.com 7 | GATE_DB_HOST=localhost 8 | GATE_DB_PORT=3306 9 | GATE_DB_NAME= 10 | GATE_DB_USER=gate 11 | GATE_DB_PASSWORD=gate 12 | CACHE_HOST=localhost 13 | CACHE_PORT=6379 14 | SECRET_KEY_BASE= 15 | SECRET_API_KEY= 16 | GATE_CONFIG_SECRET= 17 | USER_ROLES=employee,consultant 18 | UID_BUFFER=5000 19 | DEFAULT_HOST_PATTERN=s* 20 | PRODUCT_LIST=pr1,pr2 21 | SAML_APPS=datadog 22 | GATE_ORGANIZATION_NAME= 23 | GATE_ORGANIZATION_STATIC= 24 | GATE_VPN_SSL_CERT= 25 | GATE_VPN_SSL_XSIGNED= 26 | GATE_VPN_SSL_PVTKEY= 27 | NEWRELIC_AGENT_ENABLED=false 28 | NEWRELIC_LICENSE_KEY= 29 | NEWRELIC_APP_NAME=Gate 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | .local 10 | vendor/* 11 | 12 | # Ignore the default SQLite database. 13 | /db/*.sqlite3 14 | /db/*.sqlite3-journal 15 | 16 | # Ignore all logfiles and tempfiles. 17 | /log/* 18 | !/log/.keep 19 | /tmp 20 | .idea 21 | .env 22 | .ruby-gemset 23 | *.swp 24 | config/application.yml 25 | public/assets/* 26 | dump.rdb 27 | coverage 28 | data/ 29 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --format documentation 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.1.2 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | ## Releasing Gate 4 | 5 | > Gate uses semantic versioning, check [this page](https://semver.org/) for more details on how to bump the version number. 6 | 7 | Steps on releasing Gate. 8 | 9 | 1. Bump version on [VERSION](VERSION) file. 10 | 2. Add appropriate changelogs on [CHANGELOG.md](CHANGELOG.md) file. Please follow existing format. 11 | 3. Tag the commit by the new version number and push it, travis will automatically build and release Gate. 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ruby:2.4 2 | 3 | RUN apt-get update 4 | RUN curl -sL https://deb.nodesource.com/setup_10.x | bash 5 | RUN apt-get update -qq && apt-get install -y build-essential nodejs git 6 | 7 | RUN mkdir /app 8 | WORKDIR /app 9 | 10 | COPY Gemfile /app 11 | COPY Gemfile.lock /app 12 | 13 | RUN gem install bundler -v '>= 2.0' 14 | RUN bundle install --without development 15 | COPY . /app 16 | 17 | CMD [ "bundle", "exec", "rails", "s" ] 18 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rails', '7.1.3.2' 4 | 5 | gem 'activerecord-session_store' 6 | gem 'ansi' 7 | gem 'bootstrap' 8 | gem 'countries', require: 'countries/global' 9 | gem 'devise' 10 | gem 'dotenv-rails' 11 | gem 'font-awesome-rails' 12 | gem 'httparty' 13 | gem 'jbuilder' 14 | gem 'mysql2' 15 | gem 'omniauth' 16 | gem 'omniauth-google-oauth2' 17 | gem 'paranoia' 18 | gem 'puma' 19 | gem 'redis' 20 | gem 'rotp' 21 | gem 'rqrcode' 22 | 23 | gem 'sassc-rails' 24 | 25 | 26 | #Disabling SAML Feature during upgrade 27 | # #TODO ENable this feature later 28 | #gem 'ruby-saml', '1.8.0' 29 | #gem 'saml_idp', git: 'https://github.com/gate-sso/saml_idp' 30 | gem 'sdoc', group: :doc 31 | # #TODO ENable this feature later 32 | 33 | gem 'slim-rails' 34 | gem 'turbolinks' 35 | gem 'uglifier' 36 | gem 'whenever', require: false 37 | 38 | group :development, :test do 39 | gem 'capybara' 40 | gem 'coveralls' 41 | gem 'database_cleaner' 42 | gem 'dredd_hooks' 43 | gem 'factory_bot_rails' 44 | gem 'faker' 45 | gem 'mock_redis' 46 | gem 'pry' 47 | gem 'rails-controller-testing' 48 | gem 'rspec-rails' 49 | gem 'rubocop' 50 | gem 'rubocop-faker' 51 | gem 'rubocop-performance' 52 | gem 'rubocop-rails' 53 | gem 'rubocop-rspec' 54 | gem 'shoulda-matchers' 55 | gem 'simplecov' 56 | gem 'simplecov-console' 57 | gem 'timecop' 58 | gem 'webmock' 59 | end 60 | 61 | group :development do 62 | gem 'web-console', platform: :ruby 63 | end 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 gate-sso 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.1.8 2 | -------------------------------------------------------------------------------- /api_blueprint/bin/dredd_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # dredd_server.sh 3 | kill -9 $(lsof -i tcp:9865 -t) 4 | export RAILS_ENV=test 5 | export LOG_LEVEL=info 6 | rake db:drop 7 | rake db:setup 8 | bundle exec rails server --port=9865 9 | 10 | -------------------------------------------------------------------------------- /api_blueprint/hooks/dredd_hooks.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | 3 | require File.expand_path('../../config/environment', __dir__) 4 | require 'dredd_hooks/methods' 5 | 6 | include DreddHooks::Methods 7 | 8 | before_all do |_| 9 | user = User.create(name: 'foo', email: 'bar@test.com', admin: 1) 10 | access_token = AccessToken.new 11 | access_token.token = 'token' 12 | access_token.user = user 13 | user.access_token = access_token 14 | access_token.save! 15 | user.save! 16 | inactive_user = User.create(name: 'foo', email: 'foo@test2.com', active: 0, user_login_id: 'foo') 17 | inactive_user.save! 18 | active_user = User.create(name: 'foo', email: 'foo@test.com', active: 1, user_login_id: 'foo') 19 | active_user.save! 20 | end 21 | -------------------------------------------------------------------------------- /api_blueprint/vpns.apib: -------------------------------------------------------------------------------- 1 | FORMAT: 1A 2 | 3 | # API VPNS 4 | 5 | # VPNS [/api/v1/vpns] 6 | 7 | ## Create VPNS [POST] 8 | Create new vpns 9 | 10 | + Request(application/json) 11 | 12 | + Headers 13 | 14 | Authorization: token 15 | 16 | + Body 17 | 18 | { 19 | "id": 1, 20 | "name": "test-vpn", 21 | "host_name": "test-vpn.example.com", 22 | "ip_address" : "10.10.10.10" 23 | } 24 | 25 | + Schema 26 | 27 | { 28 | "type": "object", 29 | "properties" : { 30 | "id" : { 31 | "type" : int 32 | }, 33 | "name" : { 34 | "type" : "string" 35 | }, 36 | "host_name" : { 37 | "type" : "string" 38 | }, 39 | "ip_address" : { 40 | "type" : "string" 41 | } 42 | } 43 | } 44 | 45 | + Response 200 46 | 47 | + Body 48 | 49 | { 50 | "id": 1, 51 | "name": "test-vpn", 52 | "host_name": "test-vpn.example.com", 53 | "ip_address": "10.10.10.10" 54 | } 55 | 56 | + Request(application/json) 57 | 58 | + Headers 59 | 60 | Authorization: wrong-token 61 | 62 | + Body 63 | 64 | + Response 401 65 | 66 | + Headers 67 | 68 | x-frame-options: SAMEORIGIN 69 | x-xss-protection: 1; mode=block 70 | x-content-type-options: nosniff 71 | content-type: text/html 72 | cache-control: no-cache 73 | x-request-id: 73b10aa8-6f68-400b-b723-2e992ac4d000 74 | x-runtime: 0.002242 75 | connection: close 76 | transfer-encoding: chunked 77 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link application.css 2 | //= link apple-touch-icon-144x144-precomposed.png 3 | //= link apple-touch-icon-72x72-precomposed.png 4 | //= link apple-touch-icon-precomposed.png 5 | //= link favicon.ico 6 | //= link application.js 7 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/images/app_store_en_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/app_store_en_badge.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-114x114-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-114x114-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-120x120-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-120x120-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-144x144-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-144x144-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-152x152-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-152x152-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-180x180-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-180x180-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-57x57-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-57x57-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-72x72-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-72x72-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-76x76-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-76x76-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/apple-touch-icon.png -------------------------------------------------------------------------------- /app/assets/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/bg.jpg -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/google_play_en_badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/google_play_en_badge.png -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_01.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_02.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_03.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_04.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_05.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_06.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_07.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_08.png -------------------------------------------------------------------------------- /app/assets/images/saml_configure_datadog_09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/assets/images/saml_configure_datadog_09.png -------------------------------------------------------------------------------- /app/assets/javascripts/admin.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/api_resources.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | 5 | API_RESOURCE_NAME_FORMAT_ERROR_MSG = "Please enter valid name containing only alphanumeric (a-z, A-Z, 0-9), underscore (_) and dash (-)" 6 | API_RESOURCE_NAME_UNIQUENESS_ERROR_MSG = "API name already taken" 7 | API_RESOURCE_DESC_REQUIRED_ERROR_MSG = "Please enter description" 8 | 9 | api_resources_ready = -> 10 | $('#api_resource_name').on 'blur', -> 11 | valid = validate_pattern($('#api_resource_name'), '^[a-zA-Z0-9_-]+$', API_RESOURCE_NAME_FORMAT_ERROR_MSG) 12 | if valid 13 | validate_uniqueness($('#api_resource_name'), '/api_resources/search', API_RESOURCE_NAME_UNIQUENESS_ERROR_MSG) 14 | 15 | $('#api_resource_description').on 'blur', -> 16 | validate_required($('#api_resource_description'), API_RESOURCE_DESC_REQUIRED_ERROR_MSG) 17 | 18 | $('#new_api_resource').submit (event) -> 19 | if $('.is-invalid').length > 0 20 | event.preventDefault() 21 | event.stopPropagation() 22 | return 23 | 24 | $(document).on('turbolinks:load', api_resources_ready) 25 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | // require jquery3 14 | // require popper 15 | // require bootstrap-sprockets 16 | // require jquery_ujs 17 | // require turbolinks 18 | // require_tree . 19 | -------------------------------------------------------------------------------- /app/assets/javascripts/bootstrap.js.coffee: -------------------------------------------------------------------------------- 1 | jQuery -> 2 | $("a[rel~=popover], .has-popover").popover() 3 | $("a[rel~=tooltip], .has-tooltip").tooltip() 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/groups.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/home.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/host_access_groups.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/host_machine_groups.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/host_machines.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | 5 | host_machines_ready = -> 6 | $('#group_id').selectize 7 | maxItems: 1 8 | valueField: 'id' 9 | labelField: 'name' 10 | searchField: 'name' 11 | create: false 12 | render: option: (item, escape) -> 13 | '
' + escape(item.name) + '
' 14 | load: (query, callback) -> 15 | if !query.length 16 | return callback() 17 | 18 | # Use remote as source 19 | $.ajax 20 | url: '/groups/search?q=' + encodeURIComponent(query) 21 | type: 'GET' 22 | error: -> 23 | callback() 24 | return 25 | success: (res) -> 26 | callback res 27 | return 28 | return 29 | 30 | $('#group_id').on 'change', -> 31 | set_allow_submit($(this).val(), $(this)) 32 | 33 | $(document).on('turbolinks:load', host_machines_ready) 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/nss.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/omniauth_callbacks.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/profile.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/users.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | 5 | users_ready = -> 6 | $('#group_id').selectize 7 | maxItems: 1 8 | valueField: 'id' 9 | labelField: 'name' 10 | searchField: 'name' 11 | create: false 12 | render: option: (item, escape) -> 13 | '
' + escape(item.name) + '
' 14 | load: (query, callback) -> 15 | if !query.length 16 | return callback() 17 | 18 | # Use remote as source 19 | $.ajax 20 | url: '/groups/search?q=' + encodeURIComponent(query) 21 | type: 'GET' 22 | error: -> 23 | callback() 24 | return 25 | success: (res) -> 26 | callback res 27 | return 28 | return 29 | 30 | $('#group_id').on 'change', -> 31 | set_allow_submit($(this).val(), $(this)) 32 | 33 | $(document).on('turbolinks:load', users_ready) 34 | -------------------------------------------------------------------------------- /app/assets/javascripts/utilities.coffee: -------------------------------------------------------------------------------- 1 | # Utility functions 2 | 3 | @append_error_msg = (elem, res, msg) -> 4 | if !res 5 | elem.addClass('is-invalid') 6 | elem.next('.invalid-feedback').html(msg) 7 | else 8 | elem.removeClass('is-invalid') 9 | elem.next('.invalid-feedback').html('') 10 | 11 | @validate_required = (elem, msg) -> 12 | input = elem.val() 13 | append_error_msg(elem, input, msg) 14 | return !!input 15 | 16 | @validate_pattern = (elem, pattern, msg) -> 17 | input = elem.val() 18 | regex = new RegExp(pattern) 19 | validate_regex = regex.test(input) 20 | append_error_msg(elem, validate_regex, msg) 21 | return !!validate_regex 22 | 23 | @validate_uniqueness = (elem, check_url, msg) -> 24 | input = elem.val() 25 | $.ajax 26 | url: check_url + '?q=' + encodeURIComponent(input) + '&exact=true' 27 | type: 'GET' 28 | error: -> 29 | return 30 | success: (res) -> 31 | append_error_msg(elem, $.isEmptyObject(res), msg) 32 | return 33 | 34 | @set_allow_submit = (cond, elem) -> 35 | curSubmit = $("input[type=submit]", $(elem).parents('form')) 36 | if !!cond 37 | curSubmit.prop("disabled", false) 38 | else 39 | curSubmit.prop('disabled', true) 40 | return 41 | -------------------------------------------------------------------------------- /app/assets/javascripts/viewport.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | // See the Getting Started docs for more information: 8 | // http://getbootstrap.com/getting-started/#support-ie10-width 9 | 10 | (function () { 11 | 'use strict'; 12 | 13 | if (navigator.userAgent.match(/IEMobile\/10\.0/)) { 14 | var msViewportStyle = document.createElement('style') 15 | msViewportStyle.appendChild( 16 | document.createTextNode( 17 | '@-ms-viewport{width:auto!important}' 18 | ) 19 | ) 20 | document.querySelector('head').appendChild(msViewportStyle) 21 | } 22 | 23 | })(); 24 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | *= stub 'profile' 16 | *= stub 'general' 17 | */ 18 | 19 | 20 | @import url(https://fonts.googleapis.com/css?family=Roboto:300); 21 | @import url(https://fonts.googleapis.com/css?family=Lato:300); 22 | @import "bootstrap"; 23 | @import "font-awesome"; 24 | 25 | /* 26 | * https://github.com/ladjs/bootstrap-social 27 | */ 28 | @import "bootstrap-social"; 29 | a.btn { color: white!important; } 30 | .form-group .field_with_errors { display: block; background: none; } 31 | .form-group .field_with_errors label::after { content: ' *'; color: red; } 32 | body { 33 | font-family: 'Roboto', 'Lato', sans-serif; 34 | } 35 | 36 | .container-profile { 37 | max-width: 768px; 38 | min-width: 768px; 39 | } 40 | 41 | a:visited { 42 | color: blue; 43 | } 44 | /* mouse over link */ 45 | a:hover { 46 | color: blue; 47 | background: none; 48 | } 49 | .table-responsive { overflow-x: inherit; } 50 | 51 | #configAppTabsContent .tab-pane { padding-top: 20px; } 52 | #configAppTabsContent ol li { margin-top: 10px; } 53 | #configAppTabsContent li > ol { margin-bottom: 10px; } 54 | -------------------------------------------------------------------------------- /app/assets/stylesheets/general.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 70px; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/home.scss.erb: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | :root { 6 | --input-padding-x: .75rem; 7 | --input-padding-y: .75rem; 8 | } 9 | 10 | html, 11 | body { 12 | height: 100%; 13 | } 14 | @import url(https://fonts.googleapis.com/css?family=Roboto:300); 15 | @import url(https://fonts.googleapis.com/css?family=Lato:300); 16 | 17 | .home { 18 | display: -ms-flexbox; 19 | display: -webkit-box; 20 | display: flex; 21 | -ms-flex-align: center; 22 | -ms-flex-pack: center; 23 | -webkit-box-align: center; 24 | align-items: center; 25 | -webkit-box-pack: center; 26 | justify-content: center; 27 | padding-top: 40px; 28 | padding-bottom: 40px; 29 | font-family: 'Roboto', sans-serif; 30 | font-size: 16px; 31 | font-weight: 300; 32 | color: white; 33 | line-height: 30px; 34 | text-align: center; 35 | background-image: image-url('bg.jpeg'); 36 | background-size: cover; 37 | background-repeat: no-repeat; 38 | background-color: #444444; 39 | background-position: 50%; 40 | } 41 | 42 | .form-signin { 43 | width: 100%; 44 | max-width: 420px; 45 | padding: 15px; 46 | margin: 0 auto; 47 | } 48 | 49 | .token-qr table { 50 | border-width: 0; 51 | border-style: none; 52 | border-color: #0000ff; 53 | border-collapse: collapse; 54 | } 55 | 56 | .token-qr td { 57 | border-left: solid 5px #000; 58 | padding: 0; 59 | margin: 0; 60 | width: 0px; 61 | height: 5px; 62 | } 63 | 64 | .token-qr td.black { border-color: #000; } 65 | .token-qr td.white { border-color: #fff; } 66 | 67 | -------------------------------------------------------------------------------- /app/assets/stylesheets/profile.css: -------------------------------------------------------------------------------- 1 | /* Everything but the jumbotron gets side spacing for mobile first views */ 2 | 3 | .container-profile { 4 | max-width: 730px; 5 | min-width: 768px; 6 | } 7 | -------------------------------------------------------------------------------- /app/assets/stylesheets/scaffolds.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; 7 | } 8 | 9 | p, ol, ul, td { 10 | font-family: verdana, arial, helvetica, sans-serif; 11 | font-size: 13px; 12 | line-height: 18px; 13 | } 14 | 15 | pre { 16 | background-color: #eee; 17 | padding: 10px; 18 | font-size: 11px; 19 | } 20 | 21 | a { 22 | color: #000; 23 | 24 | &:visited { 25 | color: #666; 26 | } 27 | 28 | &:hover { 29 | color: #fff; 30 | background-color: #000; 31 | } 32 | } 33 | 34 | div { 35 | &.field, &.actions { 36 | margin-bottom: 10px; 37 | } 38 | } 39 | 40 | #notice { 41 | color: green; 42 | } 43 | 44 | .field_with_errors { 45 | padding: 2px; 46 | background-color: red; 47 | display: table; 48 | } 49 | 50 | #error_explanation { 51 | width: 450px; 52 | border: 2px solid red; 53 | padding: 7px; 54 | padding-bottom: 0; 55 | margin-bottom: 20px; 56 | background-color: #f0f0f0; 57 | 58 | h2 { 59 | text-align: left; 60 | font-weight: bold; 61 | padding: 5px 5px 5px 15px; 62 | font-size: 12px; 63 | margin: -7px; 64 | margin-bottom: 0px; 65 | background-color: #c00; 66 | color: #fff; 67 | } 68 | 69 | ul li { 70 | font-size: 12px; 71 | list-style: square; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/clients/data_dog_client.rb: -------------------------------------------------------------------------------- 1 | class DataDogClient 2 | include HTTParty 3 | base_uri 'https://api.datadoghq.com/api/v1' 4 | 5 | def initialize(app_key, api_key) 6 | @base_path = 'https://api.datadoghq.com/api/v1' 7 | @app_key = app_key 8 | @api_key = api_key 9 | @headers = { 10 | 'Content-Type' => 'application/json', 11 | 'Accept' => 'application/json', 12 | } 13 | end 14 | 15 | def get_user(email) 16 | url = append_auth("/user/#{email}") 17 | response = self.class.get(url, headers: @headers) 18 | if response.success? 19 | JSON.parse(response.body)['user'] 20 | else 21 | {} 22 | end 23 | end 24 | 25 | def new_user(email) 26 | url = append_auth('/user') 27 | response = self.class.post(url, body: { handle: email }.to_json, headers: @headers) 28 | if response.success? 29 | JSON.parse(response.body)['user'] 30 | else 31 | {} 32 | end 33 | end 34 | 35 | def activate_user(email) 36 | url = append_auth("/user/#{email}") 37 | response = self.class.put(url, body: { email: email, disabled: false }.to_json, headers: @headers) 38 | if response.success? 39 | JSON.parse(response.body)['user'] 40 | else 41 | {} 42 | end 43 | end 44 | 45 | def deactivate_user(email) 46 | url = append_auth("/user/#{email}") 47 | response = self.class.put(url, body: { email: email, disabled: true }.to_json, headers: @headers) 48 | if response.success? 49 | JSON.parse(response.body)['user'] 50 | else 51 | {} 52 | end 53 | end 54 | 55 | private 56 | 57 | def append_auth(str) 58 | auth_str = "api_key=#{@api_key}&application_key=#{@app_key}" 59 | str += str.include?('?') ? "&#{auth_str}" : "?#{auth_str}" 60 | str 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /app/controllers/admin_controller.rb: -------------------------------------------------------------------------------- 1 | class AdminController < ApplicationController 2 | def index; end 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/api/v1/base_controller.rb: -------------------------------------------------------------------------------- 1 | class ::Api::V1::BaseController < ActionController::Base 2 | protect_from_forgery with: :null_session 3 | before_action :authenticate_user_from_token! 4 | 5 | def authenticate_user_from_token! 6 | if get_token.nil? || !AccessToken.valid_token(get_token) 7 | raise_unauthorized 8 | end 9 | end 10 | 11 | protected 12 | 13 | def current_user 14 | access_token = AccessToken.find_token(get_token) 15 | access_token.user 16 | end 17 | 18 | private 19 | 20 | def get_token 21 | if params.key?(:access_token) 22 | params[:access_token] 23 | elsif params.key?(:token) 24 | params[:token] 25 | elsif request.headers.key?(:Authorization) 26 | request.headers[:Authorization].split(' ').last 27 | end 28 | end 29 | 30 | def raise_unauthorized 31 | head :unauthorized 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/controllers/api/v1/endpoints_controller.rb: -------------------------------------------------------------------------------- 1 | class ::Api::V1::EndpointsController < ::Api::V1::BaseController 2 | before_action :authorize_user 3 | 4 | def create 5 | endpoint = Endpoint.new(endpoint_param) 6 | if endpoint.save 7 | render json: { 8 | id: endpoint.id, 9 | path: endpoint.path, 10 | method: endpoint.method, 11 | } 12 | else 13 | render json: { status: endpoint.errors }, status: :unprocessable_entity 14 | end 15 | end 16 | 17 | def add_group 18 | endpoint = Endpoint.find_by(id: params[:id]) 19 | if endpoint.nil? 20 | return head :not_found 21 | end 22 | 23 | group = Group.find_by(group_param) 24 | group_endpoint = GroupEndpoint.new(group: group, endpoint: endpoint) 25 | 26 | if group_endpoint.save 27 | render json: {} 28 | else 29 | head :unprocessable_entity 30 | end 31 | end 32 | 33 | private 34 | 35 | def authorize_user 36 | unless current_user.admin? 37 | head :forbidden 38 | end 39 | end 40 | 41 | def group_param 42 | params.require(:group).permit(:id) 43 | end 44 | 45 | def endpoint_param 46 | params.require(:endpoint).permit(:path, :method) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /app/controllers/api/v1/groups_controller.rb: -------------------------------------------------------------------------------- 1 | class ::Api::V1::GroupsController < ::Api::V1::BaseController 2 | def create 3 | if current_user.admin? 4 | @group = Group.new(group_params) 5 | if @group.save 6 | render json: { 7 | id: @group.id, 8 | name: @group.name, 9 | }, status: :ok 10 | else 11 | is_taken = @group.errors.details[:name].select { |x| x[:error] == :taken } 12 | 13 | if !is_taken.blank? 14 | existing_group = Group.find_by(name: @group.name) 15 | render json: { 16 | status: 'group already exist', 17 | id: existing_group.id, 18 | name: existing_group.name, 19 | }, status: :unprocessable_entity 20 | else 21 | render json: { 22 | status: 'error', 23 | }, status: :unprocessable_entity 24 | end 25 | end 26 | end 27 | end 28 | 29 | def add_user 30 | @group = Group.find_by(id: params[:id]) 31 | return head :not_found unless @group.present? 32 | 33 | return raise_unauthorized unless current_user.admin? || @group.admin?(current_user) 34 | 35 | user = User.find_by(id: params[:user_id]) 36 | return head :unprocessable_entity unless user.present? 37 | 38 | expiration_date = params[:expiration_date] 39 | @group.add_user_with_expiration(params[:user_id], expiration_date) 40 | head :no_content 41 | end 42 | 43 | private 44 | 45 | def group_params 46 | params.require(:group).permit(:name) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /app/controllers/api/v1/vpns_controller.rb: -------------------------------------------------------------------------------- 1 | class ::Api::V1::VpnsController < ::Api::V1::BaseController 2 | before_action :set_vpn, only: [:assign_group] 3 | 4 | def create 5 | if current_user.admin? 6 | @vpn = Vpn.new(vpn_params) 7 | @vpn.uuid = SecureRandom.uuid 8 | if @vpn.save 9 | render json: { 10 | id: @vpn.id, 11 | name: @vpn.name, 12 | host_name: @vpn.host_name, 13 | ip_address: @vpn.ip_address, 14 | }, status: :ok 15 | else 16 | render json: { status: 'error' }, status: :unprocessable_entity 17 | end 18 | end 19 | end 20 | 21 | def assign_group 22 | if current_user.admin? 23 | @vpn.groups.delete_all 24 | @vpn.groups << Group.where(id: params[:group_id]).first 25 | render json: { status: 'group assigned' }, status: :ok 26 | end 27 | end 28 | 29 | private 30 | 31 | def set_vpn 32 | @vpn = Vpn.find(params[:id]) 33 | end 34 | 35 | def vpn_params 36 | params.require(:vpn).permit(:name, :host_name, :ip_address) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | 6 | def render_404 7 | respond_to do |format| 8 | format.html { render file: "#{Rails.root}/public/404", layout: false, status: :not_found } 9 | format.xml { head :not_found } 10 | format.any { head :not_found } 11 | end 12 | end 13 | 14 | def authenticate_access_token! 15 | unless AccessToken.valid_token(params[:token]) 16 | render_error(['Unauthorized'], :unauthorized) 17 | end 18 | end 19 | 20 | def render_error(errors, status = 400) 21 | render 'common/errors', locals: { errors: errors }, status: status 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | 3 | before_action :check_signed_in 4 | 5 | def check_signed_in 6 | redirect_to profile_path if signed_in? 7 | end 8 | 9 | def index; end 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/host_controller.rb: -------------------------------------------------------------------------------- 1 | class HostController < ApplicationController 2 | before_action :authenticate_user! 3 | def add_host 4 | @user = User.find(params[:id]) 5 | if current_user.admin? 6 | host = Host.new 7 | host.user = @user 8 | host.host_pattern = params[:host_pattern] 9 | host.save! 10 | 11 | end 12 | redirect_to user_path 13 | end 14 | 15 | def delete_host 16 | @user = User.find(params[:user_id]) 17 | if current_user.admin? 18 | @host = Host.find(params[:id]) 19 | @host.deleted_by = current_user.id 20 | @host.save! 21 | @host.destroy 22 | end 23 | 24 | redirect_to user_path(@user) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/controllers/host_machine_groups_controller.rb: -------------------------------------------------------------------------------- 1 | class HostMachineGroupsController < ApplicationController 2 | def show 3 | @host_machines = HostMachine.all 4 | end 5 | 6 | def create 7 | @host_machine = HostMachine.new(host_machine_params) 8 | respond_to do |format| 9 | @host_machine.save 10 | format.html { redirect_to :show, notice: 'host_machine was successfully created.' } 11 | format.json { render status: :created, json: "#{@host_machine.name}host created" } 12 | end 13 | end 14 | 15 | private 16 | 17 | # Use callbacks to share common setup or constraints between actions. 18 | def set_host_machine 19 | @host_machine = host_machine.find(params[:id]) 20 | end 21 | 22 | # Never trust parameters from the scary internet, only allow the white list through. 23 | def host_machine_params 24 | params.require(:host_machine).permit(:name) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/controllers/pings_controller.rb: -------------------------------------------------------------------------------- 1 | class PingsController < ApplicationController 2 | def show 3 | render plain: 'pong' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/users/auth_controller.rb: -------------------------------------------------------------------------------- 1 | class Users::AuthController < ApplicationController 2 | 3 | def log_in 4 | unless ENV['SIGN_IN_TYPE'] == 'form' 5 | return redirect_to root_path 6 | end 7 | 8 | email = params.require(:email) 9 | name = params.require(:name) 10 | 11 | unless User.valid_domain? email.split('@').last 12 | return render plain: 'Your domain is unauthorized', status: :unauthorized 13 | end 14 | 15 | user = User.create_user(name, email) 16 | user.generate_two_factor_auth 17 | sign_in_and_redirect user, event: :authentication 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /app/controllers/users/omniauth_callbacks_controller.rb: -------------------------------------------------------------------------------- 1 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 2 | def google_oauth2 3 | # You need to implement the method below in your model (e.g. app/models/user.rb) 4 | # 5 | data = request.env['omniauth.auth'] 6 | domain = data['info']['email'].split('@').last 7 | 8 | unless User.valid_domain? domain 9 | return render plain: 'Your domain is unauthorized', status: :unauthorized 10 | end 11 | 12 | @user = User.create_user(data.info['name'], data.info['email']) 13 | 14 | if @user.persisted? 15 | @user.generate_two_factor_auth 16 | sign_in_and_redirect @user, event: :authentication 17 | else 18 | session['devise.google_data'] = request.env['omniauth.auth'] 19 | redirect_to new_user_registration_url 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/vpn_domain_name_servers_controller.rb: -------------------------------------------------------------------------------- 1 | class VpnsController < ApplicationController 2 | before_action :authorize_user 3 | before_action :set_vpn, only: %i[show edit update destroy user_associated_groups] 4 | 5 | def destroy; end 6 | end 7 | 8 | #TODO fix this in future. This is something not great. 9 | class VpnDomainNameServersController < ApplicationController 10 | end 11 | -------------------------------------------------------------------------------- /app/helpers/admin_helper.rb: -------------------------------------------------------------------------------- 1 | module AdminHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/api_resources_helper.rb: -------------------------------------------------------------------------------- 1 | module ApiResourcesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def add_placeholder_to_list(list, placeholder, string_convert: 'titleize') 3 | (list.map do |row| 4 | name = string_convert.present? ? row.send(string_convert.to_sym) : row 5 | [name, row] 6 | end).insert(0, [placeholder, '']) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/helpers/group_helper.rb: -------------------------------------------------------------------------------- 1 | module GroupHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/groups_helper.rb: -------------------------------------------------------------------------------- 1 | module GroupsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/host_access_groups_helper.rb: -------------------------------------------------------------------------------- 1 | module HostAccessGroupsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/host_machine_groups_helper.rb: -------------------------------------------------------------------------------- 1 | module HostMachineGroupsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/host_machines_helper.rb: -------------------------------------------------------------------------------- 1 | module HostMachinesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/nss_helper.rb: -------------------------------------------------------------------------------- 1 | module NssHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/omniauth_callbacks_helper.rb: -------------------------------------------------------------------------------- 1 | module OmniauthCallbacksHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/profile_helper.rb: -------------------------------------------------------------------------------- 1 | module ProfileHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/lib/datadog.rb: -------------------------------------------------------------------------------- 1 | class Datadog < SamlApp 2 | 3 | def initialize(org_id) 4 | @app_name = 'datadog' 5 | super(org_id) 6 | if @config.persisted? 7 | @client = DataDogClient.new( 8 | @config.config['app_key'], 9 | @config.config['api_key'] 10 | ) 11 | else 12 | @config.config = { app_key: '', api_key: '' } 13 | end 14 | end 15 | 16 | def save_config(sso_url, config = {}) 17 | @config.config = @config.config.merge(config) 18 | super(sso_url, config) 19 | end 20 | 21 | def add_user(email) 22 | user_detail_response = @client.get_user(email) 23 | response = if user_detail_response.eql?({}) 24 | @client.new_user(email) 25 | else 26 | @client.activate_user(email) 27 | end 28 | super(email) unless response.eql?({}) 29 | end 30 | 31 | def remove_user(email) 32 | response = @client.deactivate_user(email) 33 | super(email) unless response.eql?({}) 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /app/lib/saml_app.rb: -------------------------------------------------------------------------------- 1 | class SamlApp 2 | 3 | attr_accessor :config, :app_name 4 | 5 | def initialize(org_id) 6 | @config = SamlAppConfig.find_or_initialize_by( 7 | app_name: @app_name, organisation_id: org_id 8 | ) 9 | end 10 | 11 | def save_config(sso_url, config = {}) 12 | unless @config.persisted? 13 | group_name = "#{@config.organisation.slug}_saml_#{app_name}_users" 14 | @config.group = Group.find_or_create_by(name: group_name) 15 | end 16 | @config.sso_url = sso_url 17 | @config.save 18 | end 19 | 20 | def add_user(email) 21 | user = User.where(email: email).first 22 | unless user.blank? 23 | @config.group.add_user(user.id) 24 | return true 25 | end 26 | false 27 | end 28 | 29 | def remove_user(email) 30 | user = User.where(email: email).first 31 | unless user.blank? 32 | @config.group.remove_user(user.id) 33 | return true 34 | end 35 | false 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/models/.keep -------------------------------------------------------------------------------- /app/models/access_token.rb: -------------------------------------------------------------------------------- 1 | class AccessToken < ApplicationRecord 2 | attr_accessor :token 3 | 4 | 5 | belongs_to :user 6 | 7 | before_save :hash_token! 8 | 9 | def self.find_token challenge_token 10 | AccessToken.where(hashed_token: Digest::SHA512.hexdigest(challenge_token)).first 11 | end 12 | 13 | def self.valid_token challenge_token 14 | find_token(challenge_token).present? 15 | end 16 | 17 | private 18 | 19 | def hash_token! 20 | self.hashed_token = Digest::SHA512.hexdigest self.token unless self.token.blank? 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/api_resource.rb: -------------------------------------------------------------------------------- 1 | class ApiResource < ApplicationRecord 2 | attr_accessor :access_key 3 | 4 | validates :name, format: { with: /\A[a-zA-Z0-9_-]+\Z/ }, uniqueness: true, presence: true 5 | validates :access_key, presence: true, on: :create 6 | belongs_to :user 7 | belongs_to :group 8 | 9 | before_save :hash_access_key! 10 | 11 | def self.authenticate access_key, access_token 12 | api_resource = ApiResource.find_by(hashed_access_key: Digest::SHA512.hexdigest(access_key)) 13 | user = AccessToken.find_by(hashed_token: Digest::SHA512.hexdigest(access_token)).user 14 | api_resource.group.member? user 15 | end 16 | 17 | private 18 | 19 | def hash_access_key! 20 | self.hashed_access_key = Digest::SHA512.hexdigest self.access_key unless self.access_key.blank? 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/endpoint.rb: -------------------------------------------------------------------------------- 1 | class Endpoint < ApplicationRecord 2 | 3 | 4 | has_many :group_endpoints 5 | has_many :groups, through: :group_endpoints 6 | 7 | validates_presence_of :path 8 | validates_presence_of :method 9 | validates :method, inclusion: { in: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] } 10 | validates_format_of :path, with: /\A((\/(([0-9, a-z,\-,_]+)|(:[a-z]+))+)+|\/)\Z/i 11 | end 12 | -------------------------------------------------------------------------------- /app/models/group_admin.rb: -------------------------------------------------------------------------------- 1 | class GroupAdmin < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :group 4 | end 5 | -------------------------------------------------------------------------------- /app/models/group_association.rb: -------------------------------------------------------------------------------- 1 | class GroupAssociation < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :group 4 | 5 | def self.revoke_expired(date = Date.today) 6 | where('expiration_date < ?', date).destroy_all 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/models/group_endpoint.rb: -------------------------------------------------------------------------------- 1 | class GroupEndpoint < ApplicationRecord 2 | 3 | 4 | belongs_to :group 5 | belongs_to :endpoint 6 | 7 | validates :group, uniqueness: { scope: :endpoint } 8 | validates_presence_of :group 9 | validates_presence_of :endpoint 10 | end 11 | -------------------------------------------------------------------------------- /app/models/host.rb: -------------------------------------------------------------------------------- 1 | class Host < ApplicationRecord 2 | belongs_to :user 3 | acts_as_paranoid 4 | end 5 | -------------------------------------------------------------------------------- /app/models/host_access_group.rb: -------------------------------------------------------------------------------- 1 | class HostAccessGroup < ApplicationRecord 2 | belongs_to :host_machine 3 | belongs_to :group 4 | end 5 | -------------------------------------------------------------------------------- /app/models/host_machine.rb: -------------------------------------------------------------------------------- 1 | class HostMachine < ApplicationRecord 2 | 3 | has_many :host_access_groups 4 | has_many :groups, through: :host_access_groups 5 | validates_uniqueness_of :name, case_sensitive: false 6 | validates :name, presence: true 7 | 8 | before_create :set_lower_case_name 9 | before_create :set_host_access_key 10 | 11 | def set_host_access_key 12 | self.access_key = ROTP::Base32.random_base32 13 | end 14 | 15 | def set_lower_case_name 16 | self.name = self.name.downcase 17 | end 18 | 19 | def self.get_group_response name 20 | host_machine = HostMachine.find_by_name(name) 21 | response = {} 22 | return response if host_machine.blank? 23 | response[:host_name] = name 24 | response[:groups] = host_machine.groups.collect { |g| g.name } 25 | response 26 | end 27 | 28 | def sysadmins 29 | users = GroupAssociation. 30 | select(:user_id). 31 | distinct. 32 | joins(:user). 33 | where("group_id IN (?)", groups.collect(&:id)). 34 | collect(&:user_id) 35 | end 36 | 37 | def add_host_group(name) 38 | name = name.squish 39 | if name.present? 40 | name = "#{name}_host_group" 41 | self.add_group(name.downcase) 42 | end 43 | end 44 | 45 | def add_group(name) 46 | name = name.squish 47 | if name.present? 48 | group = Group.find_or_initialize_by(name: name.downcase) 49 | self.groups << group unless self.groups.include? group 50 | self.save 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /app/models/ip_address.rb: -------------------------------------------------------------------------------- 1 | class IpAddress < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /app/models/saml_app_config.rb: -------------------------------------------------------------------------------- 1 | class SamlAppConfig < ApplicationRecord 2 | belongs_to :group 3 | belongs_to :organisation 4 | 5 | serialize :config, JSON 6 | 7 | def self.get_config(app_name, org_id) 8 | SamlAppConfig.find_or_initialize_by( 9 | app_name: app_name, organisation_id: org_id 10 | ) 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /app/models/vpn_domain_name_server.rb: -------------------------------------------------------------------------------- 1 | class VpnDomainNameServer < ApplicationRecord 2 | belongs_to :vpn 3 | end 4 | -------------------------------------------------------------------------------- /app/models/vpn_group_association.rb: -------------------------------------------------------------------------------- 1 | class VpnGroupAssociation < ApplicationRecord 2 | belongs_to :vpn 3 | belongs_to :group 4 | end 5 | 6 | -------------------------------------------------------------------------------- /app/models/vpn_group_user_association.rb: -------------------------------------------------------------------------------- 1 | class VpnGroupUserAssociation < ApplicationRecord 2 | belongs_to :vpn 3 | belongs_to :user 4 | end 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/models/vpn_search_domain.rb: -------------------------------------------------------------------------------- 1 | class VpnSearchDomain < ApplicationRecord 2 | belongs_to :vpn 3 | end 4 | -------------------------------------------------------------------------------- /app/models/vpn_supplemental_match_domain.rb: -------------------------------------------------------------------------------- 1 | class VpnSupplementalMatchDomain < ApplicationRecord 2 | belongs_to :vpn 3 | end 4 | -------------------------------------------------------------------------------- /app/validators/email_validator.rb: -------------------------------------------------------------------------------- 1 | class EmailValidator < ActiveModel::EachValidator 2 | def validate_each(record, attribute, value) 3 | unless value.to_s.match?(/\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i) 4 | record.errors[attribute] << (options[:message] || 'is not an email') 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/admin/index.html.slim: -------------------------------------------------------------------------------- 1 | h1 hello 2 | -------------------------------------------------------------------------------- /app/views/api/v1/users/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.(@user, :email, :uid, :name, :active, :admin, :home_dir, :shell, :public_key, :user_login_id, :product_name) 2 | json.groups @user.groups, :gid, :name 3 | -------------------------------------------------------------------------------- /app/views/api_resources/_api_resource.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.extract! api_resource, :id, :name, :description, :access_key, :created_at, :updated_at 2 | json.url api_resource_url(api_resource, format: :json) 3 | -------------------------------------------------------------------------------- /app/views/api_resources/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for @api_resource, :class => 'form-horizontal', html: {novalidate: 'true'} do |f| 2 | - if @api_resource.errors.any? 3 | #error_explanation 4 | h2 = "#{pluralize(@api_resource.errors.count, "error")} prohibited this api_resource from being saved:" 5 | ul 6 | - @api_resource.errors.full_messages.each do |message| 7 | li = message 8 | 9 | hr 10 | .mb-3 11 | label for="name" 12 | | API Name 13 | = f.text_field :name, required: true, class: "form-control", placeholder: "API Name" 14 | .invalid-feedback 15 | .mb-3 16 | label for="description" 17 | | Description 18 | = f.text_field :description, required: true, class: "form-control", placeholder: "Description" 19 | .invalid-feedback 20 | .mb-4 21 | = f.submit "Save", class: "btn btn-primary pull-right" 22 | -------------------------------------------------------------------------------- /app/views/api_resources/edit.html.slim: -------------------------------------------------------------------------------- 1 | h1 Editing api_resource 2 | 3 | == render 'form' 4 | 5 | => link_to 'Show', @api_resource 6 | '| 7 | =< link_to 'Back', api_resources_path 8 | 9 | -------------------------------------------------------------------------------- /app/views/api_resources/index.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-8 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | 7 | 8 | h4 API Keys 9 | 10 | table.table.responsive 11 | thead 12 | tr 13 | th Name 14 | th Description 15 | th Access key 16 | th Owner 17 | th Access Group 18 | th 19 | 20 | tbody 21 | - @api_resources.each do |api_resource| 22 | tr 23 | td = api_resource.name 24 | td = api_resource.description 25 | td = link_to 'Regenerate', regenerate_access_key_api_resource_path(api_resource), data: { confirm: 'Are you sure?' } 26 | td = link_to api_resource.user.name, api_resource.user if api_resource.user.present? 27 | td = link_to api_resource.group.name, api_resource.group if api_resource.group.present? 28 | td = link_to 'Destroy', api_resource, data: { confirm: 'Are you sure?' }, method: :delete 29 | 30 | br 31 | 32 | javascript: 33 | $("#apiresource-index").addClass("active"); 34 | -------------------------------------------------------------------------------- /app/views/api_resources/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array! @api_resources, partial: 'api_resources/api_resource', as: :api_resource 2 | -------------------------------------------------------------------------------- /app/views/api_resources/new.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | br 7 | h5 Create new API 8 | 9 | == render 'form' 10 | 11 | = link_to 'Back', api_resources_path 12 | 13 | 14 | javascript: 15 | $("#apiresource-index").addClass("active"); 16 | -------------------------------------------------------------------------------- /app/views/api_resources/show.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | br 7 | h5 Show API 8 | 9 | hr 10 | .mb-3 11 | label for="name" 12 | | API Name 13 | p.form-control-static 14 | = @api_resource.name 15 | .mb-3 16 | label for="description" 17 | | Description 18 | p.form-control-static 19 | = @api_resource.description 20 | - if flash[:access_key] 21 | .mb-3 22 | label for="access_key" 23 | | Access Key 24 | .alert.alert-warning role="alert" 25 | | Important! please make note of this access key, you will see it only this once. 26 | = text_field_tag :access_key, flash[:access_key], class: 'form-control', readonly: "" 27 | .mb-4 28 | => link_to 'Edit', edit_api_resource_path(@api_resource) 29 | '| 30 | => link_to 'Regenerate Access Key', regenerate_access_key_api_resource_path(@api_resource), :data => {:confirm => 'Are you sure?'} 31 | '| 32 | =< link_to 'Back', api_resources_path 33 | -------------------------------------------------------------------------------- /app/views/api_resources/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.partial! "api_resources/api_resource", api_resource: @api_resource 2 | -------------------------------------------------------------------------------- /app/views/application/_admin.html.slim: -------------------------------------------------------------------------------- 1 | div 2 | ul.navbar-nav 3 | li.nav-item.active 4 | a.nav-link href="#" Users 5 | li.nav-item 6 | a.nav-link href="#" Groups 7 | -------------------------------------------------------------------------------- /app/views/application/_groups_header.html.slim: -------------------------------------------------------------------------------- 1 | #notice 2 | = notice 3 | - if current_user.admin? 4 | = form_tag groups_path, method: 'post' do 5 | .row 6 | .col-md-8 7 | = text_field_tag "group[name]", "", class: "form-control", autofocus: true 8 | .col-md-4 9 | = submit_tag "Add Group", class: "form-control btn btn-sm btn-primary", name: nil 10 | 11 | br 12 | = form_tag groups_path, method: 'get' do 13 | .row 14 | .col-md-8 15 | = text_field_tag :group_search, params[:group_search], class: "form-control" , autofocus: true 16 | .col-md-4 17 | = submit_tag "Search groups", class: "form-control btn btn-sm btn-primary", name: nil 18 | 19 | hr 20 | 21 | -------------------------------------------------------------------------------- /app/views/application/_host_header.html.slim: -------------------------------------------------------------------------------- 1 | ul.nav.nav-tabs 2 | li#host_machine role="presentation" 3 | = link_to "MyHosts", host_machines_path 4 | li#group role="presentation" 5 | = link_to "Groups", groups_path 6 | li#host_machine_search role="presentation" 7 | a href="#" Search Host 8 | li#host_machine_group_search role="presentation" 9 | a href="#" Search Host Groups 10 | p 11 | br 12 | 13 | -------------------------------------------------------------------------------- /app/views/common/errors.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.success false 2 | json.errors errors 3 | -------------------------------------------------------------------------------- /app/views/groups/_form.html.slim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/views/groups/_form.html.slim -------------------------------------------------------------------------------- /app/views/groups/index.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col.container-profile 2 | - if current_user.admin? 3 | = form_tag groups_path, method: 'get', class: "p-2" do 4 | .input-group 5 | = text_field_tag :group_search, params[:group_search], class: "form-control" , autofocus: true, placeholder: "Search group name..." 6 | .input-group-append 7 | = submit_tag "Search", class: "button btn btn-secondary", name: nil 8 | 9 | 10 | - if @groups.count > 0 11 | h5 Your managed groups 12 | .table-responsive 13 | table.table.table-striped 14 | thead 15 | tr 16 | th Name 17 | th Gid 18 | th Group Admin 19 | tbody 20 | - @groups.each do |group| 21 | tr 22 | td 23 | = link_to "#{group.name}", group_path(group) 24 | td 25 | = "#{group.gid}" 26 | td 27 | - if group.group_admins.present? 28 | - group.group_admins.each do |admin| 29 | .row 30 | = "#{admin.user.try(:name)}" 31 | 32 | 33 | javascript: 34 | $("#group-index").addClass("active"); 35 | 36 | -------------------------------------------------------------------------------- /app/views/groups/new.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | h5 Add new group 3 | = form_for @group, :class => 'form-horizontal' do |f| 4 | - if @group.errors.any? 5 | #error_explanation 6 | h2 = "#{pluralize(@group.errors.count, "error")} prohibited this vpn from being saved:" 7 | ul 8 | - @group.errors.full_messages.each do |message| 9 | li = message 10 | 11 | hr 12 | .mb-3 13 | label for="name" 14 | | Name 15 | = f.text_field :name, required: true, class: "form-control", placeholder: "Group Name" 16 | .invalid-feedback 17 | | Please enter a name 18 | 19 | .mb-4 20 | = f.submit "Add Group", class: "btn btn-primary pull-right" 21 | 22 | -------------------------------------------------------------------------------- /app/views/home/index.html.slim: -------------------------------------------------------------------------------- 1 | .form-signin 2 | .row 3 | .col 4 | h1 Gate-SSO 5 | br 6 | .row 7 | .col 8 | h3 Single Sign-On 9 | br 10 | br 11 | br 12 | br 13 | - case ENV['SIGN_IN_TYPE'] 14 | - when 'form' 15 | = form_tag user_sign_in_path, method: :post do 16 | .row 17 | .col-sm-10.offset-sm-1 18 | = text_field_tag :name, '', class: 'form-control', placeholder: 'Name', required: true 19 | = text_field_tag :email, '', class: 'form-control', placeholder: 'Email', required: true, type: 'email' 20 | = submit_tag 'Sign in', class: 'form-control btn-md btn-primary' 21 | - else 22 | .row 23 | .col 24 | .col 25 | a.btn.btn-block.btn-social.btn-google href="#{url_for user_google_oauth2_omniauth_authorize_path}" 26 | span.fa.fa-google 27 | | Sign in with Google 28 | .col 29 | 30 | -------------------------------------------------------------------------------- /app/views/host_machines/index.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-6.col-md-offset-2 2 | = form_tag host_machines_path, method: 'get', class: "p-2" do 3 | .input-group 4 | = text_field_tag :host_machine_search, params[:host_machine_search], class: "form-control" , autofocus: true, placeholder: "Search host..." 5 | .input-group-append 6 | = submit_tag "Search", class: "button btn btn-secondary", name: nil 7 | 8 | 9 | 10 | 11 | .container-fluid.col-md-6.col-md-offset-2 12 | - if @host_machines.count > 0 13 | .table-responsive 14 | table.table.table-striped 15 | thead 16 | tr 17 | th Name 18 | tbody 19 | - @host_machines.each do |host_machine| 20 | tr 21 | td 22 | = link_to "#{host_machine.name}", host_machine 23 | br 24 | 25 | javascript: 26 | $("#hostmachine-index").addClass("active"); 27 | -------------------------------------------------------------------------------- /app/views/host_machines/new.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | = form_tag host_machines_path, method: 'post' do 3 | .input-group 4 | = text_field_tag "host_machine[name]", "", class: "form-control", autofocus: true 5 | .input-group 6 | = submit_tag "Add Host machine", class: "form-control btn btn-sm btn-primary", name: nil 7 | 8 | -------------------------------------------------------------------------------- /app/views/host_machines/show.html.slim: -------------------------------------------------------------------------------- 1 | .container.col-md-8 2 | h5.mb-3 Host Details 3 | hr 4 | .row 5 | .col 6 | = @host_machine.name 7 | - if current_user.admin? 8 | .card 9 | .card-body 10 | h6.card-title Configurations 11 | hr 12 | = form_tag "/host_machines/#{@host_machine.id}", method: 'put' do 13 | .row 14 | .col 15 | .custom-control.custom-checkbox 16 | = check_box "host_machine", "default_admins", class: "custom-control-input", id: "admin-checkbox" 17 | label.custom-control-label for="admin-checkbox" Default Admins? 18 | .col 19 | = submit_tag "Update", class: "form-control btn-md btn-primary" 20 | br 21 | 22 | .card 23 | .card-body 24 | .table-responsive 25 | table.table.table-striped 26 | thead 27 | tr 28 | th Group Name 29 | th 30 | tbody 31 | - @host_machine.groups.each do |group| 32 | tr 33 | td 34 | = link_to "#{group.name}", group_path(group) 35 | td 36 | = link_to "Delete", [@machine, group], method: :delete, data: {confirm: 'Are you sure to remove this machine from the group??'} if current_user.admin? 37 | br 38 | = "*This host does not have any group" if @host_machine.groups.count == 0 39 | br 40 | hr 41 | - if current_user.admin? 42 | = form_tag add_group_to_machine_path, method: :post do 43 | .row 44 | .col 45 | | Assign group 46 | .col 47 | .col 48 | = text_field_tag "group_id", "", class: "form-control" 49 | .col 50 | = submit_tag "Add group", class: "form-control btn-md btn-primary", disabled: true 51 | 52 | -------------------------------------------------------------------------------- /app/views/layouts/home.html.slim: -------------------------------------------------------------------------------- 1 | doctype html 2 | html lang="en" 3 | head 4 | link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css' 5 | meta charset="utf-8" 6 | meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" 7 | meta name="viewport" content="width=device-width, initial-scale=1.0" 8 | title= content_for?(:title) ? yield(:title) : "Gate" 9 | = csrf_meta_tags 10 | = stylesheet_link_tag "application", :media => "all" 11 | = favicon_link_tag 'apple-touch-icon-144x144-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '144x144' 12 | = favicon_link_tag 'apple-touch-icon-72x72-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png', :sizes => '72x72' 13 | = favicon_link_tag 'apple-touch-icon-precomposed.png', :rel => 'apple-touch-icon-precomposed', :type => 'image/png' 14 | = favicon_link_tag 'favicon.ico', :rel => 'shortcut icon' 15 | = javascript_include_tag "application" 16 | /! Le HTML5 shim, for IE6-8 support of HTML elements 17 | /[if lt IE 9] 18 | = javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js" 19 | 20 | 21 | body.home 22 | = yield 23 | -------------------------------------------------------------------------------- /app/views/layouts/profile.html.slim.disabled: -------------------------------------------------------------------------------- 1 | doctype html 2 | html lang="en" 3 | head 4 | meta charset="utf-8" 5 | meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" 6 | meta name="viewport" content="width=device-width, initial-scale=1.0" 7 | title= content_for?(:title) ? yield(:title) : "Gate" 8 | = csrf_meta_tags 9 | = stylesheet_link_tag "application", :media => "all" 10 | = stylesheet_link_tag 'profile' 11 | = stylesheet_link_tag "general", :media => "all" 12 | = javascript_include_tag "application" 13 | /! Le HTML5 shim, for IE6-8 support of HTML elements 14 | /[if lt IE 9] 15 | = javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js" 16 | 17 | body.profile_page 18 | .container.container-profile 19 | .header.clearfix 20 | nav 21 | ul.nav.nav-pills.pull-right 22 | li role="presentation" 23 | = link_to "Administration", admin_path if current_user.admin? 24 | li role="presentation" 25 | = link_to current_user.name, user_path(current_user.id) 26 | li.active role="presentation" 27 | = link_to "Sign out", users_sign_out_path,:method => :delete 28 | h3.text-muted Gate - Single Sign On 29 | = yield 30 | 31 | footer.footer 32 | p © 2015 Gate-SSO 33 | -------------------------------------------------------------------------------- /app/views/nss/add_host.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.success true 2 | json.access_key host.access_key 3 | json.host host.name 4 | json.groups host.groups.map(&:name) 5 | -------------------------------------------------------------------------------- /app/views/organisations/_form.html.slim: -------------------------------------------------------------------------------- 1 | - if flash.key?(:errors) 2 | .alert.alert-danger#organisation_form_errors 3 | b Issue creating application 4 | br 5 | - flash[:errors].each do |msg| 6 | = "- #{msg}" 7 | br 8 | .form-group 9 | = f.label :name 10 | = f.text_field :name, class: 'form-control' 11 | .form-group 12 | = f.label :website 13 | = f.text_field :website, class: 'form-control' 14 | .form-group 15 | = f.label :domain 16 | = f.text_field :domain, class: 'form-control' 17 | .form-group 18 | = f.label :country 19 | = f.collection_select :country, Country.all.sort_by(&:name), :gec, :name, {}, class: 'form-control' 20 | .form-group 21 | = f.label :state 22 | = f.text_field :state, class: 'form-control' 23 | .form-group 24 | = f.label :address 25 | = f.text_field :address, class: 'form-control' 26 | .form-group 27 | = f.label :admin_email_address 28 | = f.text_field :admin_email_address, class: 'form-control' 29 | .form-group 30 | = f.label :slug 31 | = f.text_field :slug, class: 'form-control' 32 | .form-group 33 | = f.label :unit_name 34 | = f.text_field :unit_name, class: 'form-control' 35 | -------------------------------------------------------------------------------- /app/views/organisations/config_saml_app.html.slim: -------------------------------------------------------------------------------- 1 | .container.col-md-8 2 | .row.mb-3.mt-2 3 | .col-md-12 4 | h5 Configure #{app_name.titleize} 5 | .row.mb-3.mt-2 6 | .col-md-12 7 | = render partial: "organisations/saml_apps/#{app_name}", locals: {org: org, app_name: app_name, saml_config: saml_config, users: users} 8 | -------------------------------------------------------------------------------- /app/views/organisations/index.html.slim: -------------------------------------------------------------------------------- 1 | .container.col-md-8 2 | .row.mb-3.mt-2 3 | .col-md-8 4 | h5 Organisations 5 | .col-md-4.text-right 6 | = link_to "New Organisation", new_organisation_path, class: "btn btn-primary", id: 'new_organisation_btn' 7 | - if flash.key?(:success) 8 | .alert.alert-success#organisation_form_success 9 | = flash[:success] 10 | - if flash.key?(:errors) 11 | .alert.alert-danger#organisation_form_errors 12 | = flash[:errors] 13 | #organisation_list.table-responsive 14 | table.table.table-striped 15 | thead 16 | tr 17 | th Name 18 | th URL 19 | th Email Domain 20 | th Actions 21 | tbody 22 | - if org_list.present? 23 | - org_list.each do |org| 24 | tr 25 | td = link_to org.name, organisation_path(org) 26 | td = link_to org.website, org.website 27 | td = org.domain 28 | td 29 | - if org.saml_setup? 30 | .dropdown.position-relative#configureAppDropDownMenuContainer 31 | button.btn.btn-primary.btn-sm.dropdown-toggle type="button" id="configureAppDropDownMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-boundary="configureAppDropDownMenuContainer" 32 | = "Configure App" 33 | .dropdown-menu aria-labelledby="configureAppDropDownMenu" 34 | = link_to "Datadog", organisation_config_saml_app_path(organisation_id: org.id, app_name: 'datadog'), class: 'dropdown-item' 35 | - else 36 | = link_to "Setup SAML", organisation_setup_saml_path(org) 37 | - else 38 | td.text-center colspan='3' 39 | p There are no organisations yet, why don't you create an organisation 40 | -------------------------------------------------------------------------------- /app/views/organisations/new.html.slim: -------------------------------------------------------------------------------- 1 | .container.col-md-8 2 | .row.mb-3.mt-2 3 | .col-md-12 4 | h5 Create Organisation 5 | hr 6 | = form_for(org) do |f| 7 | = render partial: 'form', locals: {f: f} 8 | = f.submit 'Create Organisation', class: 'btn btn-primary mb-2' 9 | -------------------------------------------------------------------------------- /app/views/organisations/show.html.slim: -------------------------------------------------------------------------------- 1 | .container.col-md-8 2 | .row.mb-3.mt-2 3 | .col-md-12 4 | h5 Update Organisation 5 | hr 6 | = form_for(org) do |f| 7 | = render partial: 'form', locals: {f: f} 8 | = f.submit 'Update Organisation', class: 'btn btn-primary mb-2' 9 | -------------------------------------------------------------------------------- /app/views/profile/_group_search.html.slim: -------------------------------------------------------------------------------- 1 | .container.container-profile 2 | = form_tag profile_group_admin_path, method: 'get' do 3 | .row 4 | .col-md-8 5 | = text_field_tag :group_search, params[:group_search], class: "form-control" , autofocus: true 6 | .col-md-4 7 | = submit_tag "Search groups", class: "form-control btn btn-sm btn-primary", name: nil 8 | 9 | hr 10 | 11 | -------------------------------------------------------------------------------- /app/views/profile/_user_search.html.slim: -------------------------------------------------------------------------------- 1 | .container.container-profile 2 | = form_tag profile_user_admin_path, method: 'get' do 3 | .row 4 | .col-md-8 5 | = text_field_tag :user_search, params[:user_search], class: "form-control" , autofocus: true 6 | .col-md-4 7 | = submit_tag "Search Users", class: "form-control btn btn-sm btn-primary", name: nil 8 | 9 | hr 10 | -------------------------------------------------------------------------------- /app/views/profile/group_admin.html.slim: -------------------------------------------------------------------------------- 1 | = render partial: "group_search" 2 | -------------------------------------------------------------------------------- /app/views/profile/list.html.slim: -------------------------------------------------------------------------------- 1 | = render partial: "user_search" 2 | - if @users.count > 0 3 | .table-responsive 4 | table.table.table-striped 5 | thead 6 | tr 7 | th Name 8 | th Email 9 | th Is Active? 10 | th Is Admin? 11 | tbody 12 | - @users.each do |user| 13 | tr 14 | td 15 | = link_to "#{user.name}", user_path(user) 16 | td 17 | = "#{user.email}" 18 | td 19 | = "#{user.active.to_s.camelcase}" 20 | td 21 | = "#{user.admin.to_s.camelcase}" 22 | -------------------------------------------------------------------------------- /app/views/profile/public_key.html.slim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/app/views/profile/public_key.html.slim -------------------------------------------------------------------------------- /app/views/profile/user_admin.html.slim: -------------------------------------------------------------------------------- 1 | = render partial: "user_search" 2 | -------------------------------------------------------------------------------- /app/views/users/_search.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | = form_tag users_path, method: 'get', class: "p-2" do 3 | .input-group 4 | = text_field_tag :user_search, params[:user_search], class: "form-control" , autofocus: true, placeholder: "Search user name..." 5 | .input-group-append 6 | = submit_tag "Search", class: "button btn btn-secondary", name: nil 7 | 8 | -------------------------------------------------------------------------------- /app/views/users/index.html.slim: -------------------------------------------------------------------------------- 1 | = render partial: "search" 2 | - if @users.count > 0 3 | .table-responsive 4 | table.table.table-striped 5 | thead 6 | tr 7 | th Name 8 | th Email 9 | th Is Active? 10 | th Is Admin? 11 | tbody 12 | - @users.each do |user| 13 | tr 14 | td 15 | = link_to "#{user.name}", user_path(user) 16 | td 17 | = "#{user.email}" 18 | td 19 | = "#{user.active.to_s.camelcase}" 20 | td 21 | = "#{user.admin.to_s.camelcase}" 22 | 23 | javascript: 24 | $("#user-index").addClass("active"); 25 | -------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
Create User
5 |
6 | <%= form_for(User.new) do |f| %> 7 | <% if flash.key?(:errors) %> 8 |
9 | Issue Creating User
10 | <%= flash[:errors].map { |msg| "- #{msg}".html_safe }.join("
").html_safe %> 11 |
12 | <% end %> 13 |
14 | <%= f.label :first_name %> 15 | <%= f.text_field :first_name, class: 'form-control' %> 16 |
17 |
18 | <%= f.label :last_name %> 19 | <%= f.text_field :last_name, class: 'form-control' %> 20 |
21 |
22 | <%= f.label :mobile %> 23 | <%= f.text_field :mobile, class: 'form-control' %> 24 |
25 |
26 | <%= f.label :alternate_email %> 27 | <%= f.text_field :alternate_email, class: 'form-control' %> 28 |
29 |
30 | <%= f.label :user_role %> 31 | <%= f.select :user_role, add_placeholder_to_list(roles, "Select A Role"), {}, class: 'form-control' %> 32 |
33 |
34 | <%= label_tag :domain %> 35 | <%= select_tag :user_domain, options_for_select(add_placeholder_to_list(domains, "Select A Domain", string_convert: '')), class: 'form-control' %> 36 |
37 | <%= f.submit 'Create User', class: 'btn btn-primary mb-2' %> 38 | <% end %> 39 |
40 |
41 |
-------------------------------------------------------------------------------- /app/views/vpns/_form.html.slim: -------------------------------------------------------------------------------- 1 | = form_for @vpn, :class => 'form-horizontal' do |f| 2 | - if @vpn.errors.any? 3 | #error_explanation 4 | h2 = "#{pluralize(@vpn.errors.count, "error")} prohibited this vpn from being saved:" 5 | ul 6 | - @vpn.errors.full_messages.each do |message| 7 | li = message 8 | 9 | hr 10 | .mb-3 11 | label for="name" 12 | | Name 13 | = f.text_field :name, required: true, class: "form-control", placeholder: "VPN Name" 14 | .mb-3 15 | label for="host_name" 16 | | Host name 17 | = f.text_field :host_name, required: true, class: "form-control", placeholder: "Host name" 18 | .invalid-feedback 19 | | Please enter host name. 20 | .mb-3 21 | label for="ip_address" 22 | | IP Address 23 | = f.text_field :ip_address, required: true, class: 'form-control', placeholder: "IP address" 24 | .invalid-feedback 25 | | Please enter IP address. 26 | 27 | .mb-4 28 | = f.submit "Save", class: "btn btn-primary pull-right" 29 | 30 | -------------------------------------------------------------------------------- /app/views/vpns/edit.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | br 7 | h5 Edit VPN Details 8 | = render "form" 9 | 10 | javascript: 11 | $("#vpn-index").addClass("active"); 12 | 13 | -------------------------------------------------------------------------------- /app/views/vpns/index.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-8.col-md-offset-4 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | 7 | - if Vpn.administrator? current_user 8 | h5 Managed VPNs 9 | table.table.responsive 10 | thead 11 | tr 12 | th="Name" 13 | th="Hostname" 14 | th="IP Address" 15 | - Vpn.managed_vpns(current_user).each do |vpn| 16 | tbody 17 | tr 18 | td= link_to vpn.name, vpn 19 | td= vpn.host_name 20 | td= vpn.ip_address 21 | 22 | h5 23 | b Listing VPNs 24 | table.table.responsive 25 | thead 26 | tr 27 | th="Name" 28 | th="Hostname" 29 | th="IP Address" 30 | th 31 | 32 | tbody 33 | - @vpns.each do |vpn| 34 | tr 35 | td= link_to vpn.name, vpn 36 | td= vpn.host_name 37 | td= vpn.ip_address 38 | td= link_to "Delete", vpn, method: :delete, data: {confirm: 'Are you sure to remove this vpn from gate?'} if current_user.admin? 39 | 40 | javascript: 41 | $("#vpn-index").addClass("active"); 42 | -------------------------------------------------------------------------------- /app/views/vpns/new.html.slim: -------------------------------------------------------------------------------- 1 | .container-fluid.col-md-4.col-md-offset-4 2 | - if notice.present? 3 | .alert.alert-primary role="alert" 4 | #notice 5 | = notice 6 | br 7 | h5 Add new VPN 8 | = render "form" 9 | 10 | javascript: 11 | $("#vpn-index").addClass("active"); 12 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Gate 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 5.0 13 | 14 | # Configuration for the application, engines, and railties goes here. 15 | # 16 | # These settings can be overridden in specific environments using the files 17 | # in config/environments, which are processed later. 18 | # 19 | # config.time_zone = "Central Time (US & Canada)" 20 | # config.eager_load_paths << Rails.root.join("extras") 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: mysql2 3 | pool: 5 4 | timeout: 5000 5 | host: <%= ENV['GATE_DB_HOST'] %> 6 | port: <%= ENV['GATE_DB_PORT'] %> 7 | username: <%= ENV['GATE_DB_USER'] %> 8 | password: <%= ENV['GATE_DB_PASSWORD'] %> 9 | 10 | 11 | development: 12 | <<: *default 13 | database: gate_development 14 | host: localhost 15 | post: 3306 16 | username: gate_development 17 | password: password 18 | properties: 19 | useSSL: false 20 | 21 | test: 22 | <<: *default 23 | database: gate_test 24 | host: localhost 25 | post: 3306 26 | username: gate_test 27 | password: password 28 | properties: 29 | useSSL: false 30 | 31 | integration: 32 | <<: *default 33 | database: <%= ENV['GATE_DB_NAME'] %> 34 | 35 | production: 36 | <<: *default 37 | pool: 16 38 | database: <%= ENV['GATE_DB_NAME'] %> 39 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in the app/assets 11 | # folder are already added. 12 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 13 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap and inline scripts 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/dotenv.rb: -------------------------------------------------------------------------------- 1 | begin 2 | Dotenv.require_keys('GATE_DB_HOST', 3 | 'GATE_DB_PORT', 4 | 'GATE_DB_USER', 5 | 'GATE_DB_PASSWORD', 6 | 'CACHE_HOST', 7 | 'CACHE_PORT', 8 | 'GATE_HOSTED_DOMAINS', 9 | 'GATE_HOSTED_DOMAIN') 10 | rescue => exception 11 | puts exception.to_s 12 | exit(-1) 13 | end 14 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be filtered from the log file. Use this to limit dissemination of 4 | # sensitive information. See the ActiveSupport::ParameterFilter documentation for supported 5 | # notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Rails 5.0 release notes for more info on each option. 8 | 9 | # Enable per-form CSRF tokens. Previous versions had false. 10 | #Rails.application.config.action_controller.per_form_csrf_tokens = false 11 | 12 | # Enable origin-checking CSRF mitigation. Previous versions had false. 13 | #Rails.application.config.action_controller.forgery_protection_origin_check = false 14 | 15 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 16 | # Previous versions had false. 17 | #ActiveSupport.to_time_preserves_timezone = false 18 | 19 | # Require `belongs_to` associations by default. Previous versions had false. 20 | #Rails.application.config.active_record.belongs_to_required_by_default = false 21 | 22 | -------------------------------------------------------------------------------- /config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP permissions policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.permissions_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :active_record_store, key: '_gate_session' 4 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | breadcrumbs: 6 | application: 7 | root: "Index" 8 | pages: 9 | pages: "Pages" 10 | helpers: 11 | actions: "Actions" 12 | links: 13 | back: "Back" 14 | cancel: "Cancel" 15 | confirm: "Are you sure?" 16 | destroy: "Delete" 17 | new: "New" 18 | edit: "Edit" 19 | titles: 20 | edit: "Edit %{model}" 21 | save: "Save %{model}" 22 | new: "New %{model}" 23 | delete: "Delete %{model}" 24 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /config/newrelic.yml: -------------------------------------------------------------------------------- 1 | common: &default_settings 2 | # Required license key associated with your New Relic account. 3 | license_key: <%= ENV['NEWRELIC_LICENSE_KEY'] %> 4 | 5 | # Your application name. Renaming here affects where data displays in New 6 | # Relic. For more details, see https://docs.newrelic.com/docs/apm/new-relic-apm/maintenance/renaming-applications 7 | app_name: <%= ENV['NEWRELIC_APP_NAME'] %> 8 | 9 | # To disable the agent regardless of other settings, uncomment the following: 10 | agent_enabled: <%= ENV['NEWRELIC_AGENT_ENABLED'] == 'true' %> 11 | 12 | # Logging level for log/newrelic_agent.log 13 | log_level: info 14 | 15 | 16 | # Environment-specific settings are in this section. 17 | # RAILS_ENV or RACK_ENV (as appropriate) is used to determine the environment. 18 | # If your application has other named environments, configure them here. 19 | development: 20 | <<: *default_settings 21 | app_name: <%= ENV['NEWRELIC_APP_NAME'] + "(Development)" %> 22 | 23 | test: 24 | <<: *default_settings 25 | # It doesn't make sense to report to New Relic from automated test runs. 26 | monitor_mode: false 27 | 28 | production: 29 | <<: *default_settings 30 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum, this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # The code in the `on_worker_boot` will be called if you are using 36 | # clustered mode by specifying a number of `workers`. After each worker 37 | # process is booted this block will be run, if you are using `preload_app!` 38 | # option you will want to use this block to reconnect to any threads 39 | # or connections that may have been created at application boot, Ruby 40 | # cannot share connections between processes. 41 | # 42 | # on_worker_boot do 43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 44 | # end 45 | 46 | # Allow puma to be restarted by `rails restart` command. 47 | plugin :tmp_restart 48 | -------------------------------------------------------------------------------- /config/redis.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | host: <%= ENV['CACHE_HOST'] %> 3 | port: <%= ENV['CACHE_PORT'] %> 4 | limit: 20 5 | 6 | development: 7 | <<: *default 8 | 9 | test: 10 | <<: *default 11 | 12 | integration: 13 | <<: *default 14 | 15 | production: 16 | <<: *default 17 | -------------------------------------------------------------------------------- /config/schedule.rb: -------------------------------------------------------------------------------- 1 | # Use this file to easily define all of your cron jobs. 2 | # 3 | # It's helpful, but not entirely necessary to understand cron before proceeding. 4 | # http://en.wikipedia.org/wiki/Cron 5 | 6 | # Example: 7 | # 8 | # set :output, "/path/to/my/cron_log.log" 9 | # 10 | # every 2.hours do 11 | # command "/usr/bin/some_great_command" 12 | # runner "MyModel.some_method" 13 | # rake "some:great:rake:task" 14 | # end 15 | # 16 | # every 4.days do 17 | # runner "AnotherModel.prune_old_records" 18 | # end 19 | 20 | # Learn more: http://github.com/javan/whenever 21 | 22 | every 1.day, at: '2:00 am' do 23 | rake 'users:purge_inactive' 24 | rake 'users:revoke_expired_membership' 25 | end 26 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 6a4735f30c7ab8c09019b80cbfd60ba2ead1d1c6b2c60632522602f002460d4590741f9e6713b89e67fd298bd155ff4f5d2f010a09c19388b0a209bb4841a2f8 15 | 16 | test: 17 | secret_key_base: b575eb4f653d58f0b666df115bc91026211573c0224a516e0e20d8b2817d268df6183dd4a028a38780c7b5846e255af900de9319e395cc3e004a387fadb99555 18 | 19 | integration: 20 | secret_key_base: <%= ENV['SECRET_KEY_BASE'] %> 21 | secret_api_key: <%= ENV['SECRET_API_KEY'] %> 22 | 23 | # Do not keep production secrets in the repository, 24 | # instead read values from the environment. 25 | production: 26 | secret_key_base: <%= ENV['SECRET_KEY_BASE'] %> 27 | secret_api_key: <%= ENV['SECRET_API_KEY'] %> 28 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket-<%= Rails.env %> 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket-<%= Rails.env %> 23 | 24 | # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name-<%= Rails.env %> 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /db/migrate/20160419122430_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :users do |t| 4 | ## Database authenticatable 5 | t.string :email, null: false, default: "" 6 | t.string :encrypted_password, null: false, default: "" 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, default: 0, null: false 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.string :current_sign_in_ip 20 | t.string :last_sign_in_ip 21 | 22 | ## Confirmable 23 | # t.string :confirmation_token 24 | # t.datetime :confirmed_at 25 | # t.datetime :confirmation_sent_at 26 | # t.string :unconfirmed_email # Only if using reconfirmable 27 | 28 | ## Lockable 29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 30 | # t.string :unlock_token # Only if unlock strategy is :email or :both 31 | # t.datetime :locked_at 32 | 33 | 34 | t.timestamps null: false 35 | end 36 | 37 | add_index :users, :email, unique: true 38 | add_index :users, :reset_password_token, unique: true 39 | # add_index :users, :confirmation_token, unique: true 40 | # add_index :users, :unlock_token, unique: true 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /db/migrate/20160419132647_add_provider_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddProviderToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :provider, :string 4 | add_column :users, :uid, :string 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20160419144739_add_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddNameToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160427123146_add_auth_key_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddAuthKeyToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :auth_key, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160427123233_add_provisioning_uri_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddProvisioningUriToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :provisioning_uri, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160519042340_add_active_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddActiveToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :active, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160519064340_add_default_value_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddDefaultValueToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | change_column :users, :active, :boolean, default: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160615044834_create_hosts.rb: -------------------------------------------------------------------------------- 1 | class CreateHosts < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :hosts do |t| 4 | t.string :host_pattern 5 | 6 | t.timestamps null: false 7 | end 8 | add_index :hosts, :host_pattern 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20160615045052_add_admin_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :admin, :boolean, default: false 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160615112805_add_user_to_host.rb: -------------------------------------------------------------------------------- 1 | class AddUserToHost < ActiveRecord::Migration[5.0] 2 | def change 3 | add_reference :hosts, :user, index: true, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160628140022_add_deleted_at_to_host.rb: -------------------------------------------------------------------------------- 1 | class AddDeletedAtToHost < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :hosts, :deleted_at, :datetime 4 | add_index :hosts, :deleted_at 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20160628140440_add_deleted_by_to_host.rb: -------------------------------------------------------------------------------- 1 | class AddDeletedByToHost < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :hosts, :deleted_by, :integer 4 | add_index :hosts, :deleted_by 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20160629043358_add_homedir_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddHomedirToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :home_dir, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160629043415_add_shell_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddShellToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :shell, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160629075435_create_groups.rb: -------------------------------------------------------------------------------- 1 | class CreateGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :groups do |t| 4 | t.string :name 5 | t.integer :gid 6 | 7 | t.timestamps null: false 8 | end 9 | add_index :groups, :name 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20160701090045_create_group_associations.rb: -------------------------------------------------------------------------------- 1 | class CreateGroupAssociations < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :group_associations do |t| 4 | t.references :user 5 | t.references :group 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20160701112600_add_deleted_properties_to_group.rb: -------------------------------------------------------------------------------- 1 | class AddDeletedPropertiesToGroup < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :groups, :deleted_by, :integer 4 | add_column :groups, :deleted_at, :datetime 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20160707115313_create_access_tokens.rb: -------------------------------------------------------------------------------- 1 | class CreateAccessTokens < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :access_tokens do |t| 4 | t.string :token 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20160714115228_add_public_key_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddPublicKeyToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :public_key, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20160908081651_create_host_machines.rb: -------------------------------------------------------------------------------- 1 | class CreateHostMachines < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :host_machines do |t| 4 | t.string :name 5 | 6 | t.timestamps null: false 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20161003145832_create_host_access_groups.rb: -------------------------------------------------------------------------------- 1 | class CreateHostAccessGroups < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :host_access_groups do |t| 4 | t.references :host_machine 5 | t.references :group 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20170803140620_add_user_login_id_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddUserLoginIdToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :user_login_id, :string 4 | add_index :users, :user_login_id 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20171013115441_create_versions.rb: -------------------------------------------------------------------------------- 1 | # This migration creates the `versions` table, the only schema PT requires. 2 | # All other migrations PT provides are optional. 3 | class CreateVersions < ActiveRecord::Migration[5.0] 4 | 5 | # The largest text column available in all supported RDBMS is 6 | # 1024^3 - 1 bytes, roughly one gibibyte. We specify a size 7 | # so that MySQL will use `longtext` instead of `text`. Otherwise, 8 | # when serializing very large objects, `text` might not be big enough. 9 | TEXT_BYTES = 1_073_741_823 10 | 11 | def change 12 | #create_table :versions, { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" } do |t| 13 | create_table :versions do |t| 14 | t.string :item_type, {:null=>false, :limit=>191} 15 | t.integer :item_id, null: false 16 | t.string :event, null: false 17 | t.string :whodunnit 18 | t.text :object, limit: TEXT_BYTES 19 | t.text :object_changes # Optional column-level changes 20 | 21 | # Known issue in MySQL: fractional second precision 22 | # ------------------------------------------------- 23 | # 24 | # MySQL timestamp columns do not support fractional seconds unless 25 | # defined with "fractional seconds precision". MySQL users should manually 26 | # add fractional seconds precision to this migration, specifically, to 27 | # the `created_at` column. 28 | # (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html) 29 | # 30 | # MySQL users should also upgrade to rails 4.2, which is the first 31 | # version of ActiveRecord with support for fractional seconds in MySQL. 32 | # (https://github.com/rails/rails/pull/14359) 33 | # 34 | t.datetime :created_at 35 | end 36 | add_index :versions, %i(item_type item_id) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /db/migrate/20171016064705_remove_index_group_name.rb: -------------------------------------------------------------------------------- 1 | class RemoveIndexGroupName < ActiveRecord::Migration[5.0] 2 | def change 3 | remove_index :groups, [:name] 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171016071526_add_unique_index_on_groups_name.rb: -------------------------------------------------------------------------------- 1 | class AddUniqueIndexOnGroupsName < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :groups, :name, unique: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171031060034_create_group_admin.rb: -------------------------------------------------------------------------------- 1 | class CreateGroupAdmin < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :group_admins do |t| 4 | t.integer :group_id 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20171031060217_add_foreign_key_ref_on_group_admin.rb: -------------------------------------------------------------------------------- 1 | class AddForeignKeyRefOnGroupAdmin < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key :group_admins, :groups 4 | add_foreign_key :group_admins, :users 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20171031100758_create_vpns.rb: -------------------------------------------------------------------------------- 1 | class CreateVpns < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpns do |t| 4 | t.string :name 5 | t.string :host_name 6 | t.string :url 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20171031101026_create_vpn_group_association.rb: -------------------------------------------------------------------------------- 1 | class CreateVpnGroupAssociation < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpn_group_associations do |t| 4 | t.integer :group_id 5 | t.integer :vpn_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20171031103518_add_foreign_key_ref_on_vpn_group_association.rb: -------------------------------------------------------------------------------- 1 | class AddForeignKeyRefOnVpnGroupAssociation < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key :vpn_group_associations, :groups 4 | add_foreign_key :vpn_group_associations, :vpns 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20171031113123_create_vpn_group_user_association.rb: -------------------------------------------------------------------------------- 1 | class CreateVpnGroupUserAssociation < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpn_group_user_associations do |t| 4 | t.integer :user_id 5 | t.integer :vpn_id 6 | t.integer :group_id 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20171031121702_add_foreign_key_ref_on_vpn_group_user_association.rb: -------------------------------------------------------------------------------- 1 | class AddForeignKeyRefOnVpnGroupUserAssociation < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key :vpn_group_user_associations, :users 4 | add_foreign_key :vpn_group_user_associations, :groups 5 | add_foreign_key :vpn_group_user_associations, :vpns 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20171102071909_add_ip_address_to_vpns.rb: -------------------------------------------------------------------------------- 1 | class AddIpAddressToVpns < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :vpns, :ip_address, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171107114249_remove_url_from_vpns.rb: -------------------------------------------------------------------------------- 1 | class RemoveUrlFromVpns < ActiveRecord::Migration[5.0] 2 | def change 3 | remove_column :vpns, :url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171108130234_add_user_id_to_access_token.rb: -------------------------------------------------------------------------------- 1 | class AddUserIdToAccessToken < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :access_tokens, :user_id, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171108130353_add_foreign_key_ref_on_access_tokens.rb: -------------------------------------------------------------------------------- 1 | class AddForeignKeyRefOnAccessTokens < ActiveRecord::Migration[5.0] 2 | def change 3 | add_foreign_key "access_tokens", "users" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171124090240_add_uuid_to_vpns.rb: -------------------------------------------------------------------------------- 1 | class AddUuidToVpns < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :vpns, :uuid, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20171124114427_create_vpn_domain_name_servers.rb: -------------------------------------------------------------------------------- 1 | class CreateVpnDomainNameServers < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpn_domain_name_servers do |t| 4 | t.integer :vpn_id 5 | t.string :server_address 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20171124114830_create_vpn_search_domains.rb: -------------------------------------------------------------------------------- 1 | class CreateVpnSearchDomains < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpn_search_domains do |t| 4 | t.integer :vpn_id 5 | t.string :search_domain 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20171124115925_create_vpn_supplemental_match_domains.rb: -------------------------------------------------------------------------------- 1 | class CreateVpnSupplementalMatchDomains < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :vpn_supplemental_match_domains do |t| 4 | t.integer :vpn_id 5 | t.string :supplemental_match_domain 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20180104081814_add_product_name_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddProductNameToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :product_name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180202102206_create_saml_service_providers.rb: -------------------------------------------------------------------------------- 1 | class CreateSamlServiceProviders < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :saml_service_providers do |t| 4 | t.string :name, null: false, unique: true 5 | t.string :sso_url, null: false, unique: true 6 | t.string :metadata_url, null: false, unique: true 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20180214050204_add_api_key_to_host_machines.rb: -------------------------------------------------------------------------------- 1 | class AddApiKeyToHostMachines < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :host_machines, :api_key, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180214052451_create_ip_addresses.rb: -------------------------------------------------------------------------------- 1 | class CreateIpAddresses < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :ip_addresses do |t| 4 | t.string :address 5 | t.string :mac_address 6 | 7 | t.timestamps null: false 8 | end 9 | add_index :ip_addresses, :address 10 | add_index :ip_addresses, :mac_address 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20180214052644_add_host_machine_to_ip_address.rb: -------------------------------------------------------------------------------- 1 | class AddHostMachineToIpAddress < ActiveRecord::Migration[5.0] 2 | def change 3 | add_reference :ip_addresses, :host_machine, index: true, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180219150818_add_description_to_group.rb: -------------------------------------------------------------------------------- 1 | class AddDescriptionToGroup < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :groups, :description, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180222135930_add_access_key_to_host_machine.rb: -------------------------------------------------------------------------------- 1 | class AddAccessKeyToHostMachine < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :host_machines, :access_key, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180222140000_add_access_key_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddAccessKeyToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :access_key, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180227051732_create_api_resources.rb: -------------------------------------------------------------------------------- 1 | class CreateApiResources < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :api_resources do |t| 4 | t.string :name 5 | t.string :description 6 | t.string :access_key 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20180301010021_add_user_to_api_resources.rb: -------------------------------------------------------------------------------- 1 | class AddUserToApiResources < ActiveRecord::Migration[5.0] 2 | def change 3 | add_reference :api_resources, :user, index: true, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180301010035_add_group_to_api_resources.rb: -------------------------------------------------------------------------------- 1 | class AddGroupToApiResources < ActiveRecord::Migration[5.0] 2 | def change 3 | add_reference :api_resources, :group, index: true, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180306231200_add_deactivated_at_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddDeactivatedAtToUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :deactivated_at, :datetime 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180311082600_rename_access_key_in_api_resources.rb: -------------------------------------------------------------------------------- 1 | class RenameAccessKeyInApiResources < ActiveRecord::Migration[5.0] 2 | def change 3 | rename_column :api_resources, :access_key, :hashed_access_key 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180311161200_rename_token_in_access_tokens.rb: -------------------------------------------------------------------------------- 1 | class RenameTokenInAccessTokens < ActiveRecord::Migration[5.0] 2 | def change 3 | rename_column :access_tokens, :token, :hashed_token 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180318083000_create_indexes_to_speedup_nss_controller.rb: -------------------------------------------------------------------------------- 1 | class CreateIndexesToSpeedupNssController < ActiveRecord::Migration[5.0] 2 | def change 3 | add_index :users, :uid 4 | add_index :access_tokens, :hashed_token 5 | add_index :host_machines, :access_key 6 | add_index :host_access_groups, [:host_machine_id, :group_id] 7 | add_index :group_associations, [:group_id, :user_id] 8 | add_index :groups, :gid 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20180613074108_create_organisations.rb: -------------------------------------------------------------------------------- 1 | class CreateOrganisations < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :organisations do |t| 4 | t.string :name 5 | t.string :url 6 | t.string :email_domain 7 | 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20180613165050_drop_saml_service_providers.rb: -------------------------------------------------------------------------------- 1 | class DropSamlServiceProviders < ActiveRecord::Migration[5.0] 2 | def change 3 | drop_table :saml_service_providers 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180723175600_update_organisations_for_saml.rb: -------------------------------------------------------------------------------- 1 | class UpdateOrganisationsForSaml < ActiveRecord::Migration[5.0] 2 | def change 3 | rename_column :organisations, :url, :website 4 | rename_column :organisations, :email_domain, :domain 5 | add_column :organisations, :country, :string 6 | add_column :organisations, :state, :string 7 | add_column :organisations, :address, :string 8 | add_column :organisations, :unit_name, :string 9 | add_column :organisations, :admin_email_address, :string 10 | add_column :organisations, :slug, :string 11 | add_column :organisations, :cert_fingerprint, :string 12 | add_column :organisations, :cert_key, :text 13 | add_column :organisations, :cert_private_key, :text 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20181002023107_add_default_admins_to_host_machines.rb: -------------------------------------------------------------------------------- 1 | class AddDefaultAdminsToHostMachines < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :host_machines, :default_admins, :boolean, default: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20181016093315_create_saml_app_configs.rb: -------------------------------------------------------------------------------- 1 | class CreateSamlAppConfigs < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :saml_app_configs do |t| 4 | t.references :group, foreign_key: true 5 | t.string :sso_url 6 | t.json :config 7 | t.references :organisation, foreign_key: true 8 | t.string :app_name 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20181208184236_add_fields_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddFieldsToUser < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :users, :first_name, :string 4 | add_column :users, :last_name, :string 5 | add_column :users, :user_role, :string 6 | add_column :users, :mobile, :string 7 | add_column :users, :alternate_email, :string 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20190624024930_add_expiration_date_to_group_associations.rb: -------------------------------------------------------------------------------- 1 | class AddExpirationDateToGroupAssociations < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :group_associations, :expiration_date, :date 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20190820070910_create_endpoints.rb: -------------------------------------------------------------------------------- 1 | class CreateEndpoints < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :endpoints do |t| 4 | t.string :path, null: false 5 | t.string :method, null: false 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190820075040_create_group_endpoints.rb: -------------------------------------------------------------------------------- 1 | class CreateGroupEndpoints < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :group_endpoints do |t| 4 | t.integer :group_id 5 | t.bigint :endpoint_id 6 | 7 | t.timestamps null: false 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190820080624_add_foreign_key_ref_on_group_endpoints.rb: -------------------------------------------------------------------------------- 1 | class AddForeignKeyRefOnGroupEndpoints < ActiveRecord::Migration[5.1] 2 | def change 3 | add_foreign_key :group_endpoints, :groups 4 | add_foreign_key :group_endpoints, :endpoints 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20200113065717_add_sessions_table.rb: -------------------------------------------------------------------------------- 1 | class AddSessionsTable < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :sessions do |t| 4 | t.string :session_id, :null => false 5 | t.text :data 6 | t.timestamps 7 | end 8 | 9 | add_index :sessions, :session_id, :unique => true 10 | add_index :sessions, :updated_at 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20220926001848_add_service_name_to_active_storage_blobs.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20190112182829) 2 | class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] 3 | def up 4 | return unless table_exists?(:active_storage_blobs) 5 | 6 | unless column_exists?(:active_storage_blobs, :service_name) 7 | add_column :active_storage_blobs, :service_name, :string 8 | 9 | if configured_service = ActiveStorage::Blob.service.name 10 | ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) 11 | end 12 | 13 | change_column :active_storage_blobs, :service_name, :string, null: false 14 | end 15 | end 16 | 17 | def down 18 | return unless table_exists?(:active_storage_blobs) 19 | 20 | remove_column :active_storage_blobs, :service_name 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /db/migrate/20220926001849_create_active_storage_variant_records.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20191206030411) 2 | class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] 3 | def change 4 | return unless table_exists?(:active_storage_blobs) 5 | 6 | # Use Active Record's configured type for primary key 7 | create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t| 8 | t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type 9 | t.string :variation_digest, null: false 10 | 11 | t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true 12 | t.foreign_key :active_storage_blobs, column: :blob_id 13 | end 14 | end 15 | 16 | private 17 | def primary_key_type 18 | config = Rails.configuration.generators 19 | config.options[config.orm][:primary_key_type] || :primary_key 20 | end 21 | 22 | def blobs_primary_key_type 23 | pkey_name = connection.primary_key(:active_storage_blobs) 24 | pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } 25 | pkey_column.bigint? ? :bigint : pkey_column.type 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /db/migrate/20220926001850_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20211119233751) 2 | class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0] 3 | def change 4 | return unless table_exists?(:active_storage_blobs) 5 | 6 | change_column_null(:active_storage_blobs, :checksum, true) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # 5 | # this file loads seeds based on environments - so please be aware to run appropriate seed file 6 | # 7 | load(Rails.root.join( 'db', 'seeds', "#{Rails.env.downcase}.rb")) 8 | -------------------------------------------------------------------------------- /db/seeds/development.rb: -------------------------------------------------------------------------------- 1 | dev_user = User.create_user('dev', 'dev@a.c') 2 | dev_user.generate_two_factor_auth 3 | (1..6).each do |uid| 4 | user = User.create_user("dev#{uid}", "dev#{uid}@a.c") 5 | user.generate_two_factor_auth 6 | end 7 | group = Group.create(name: 'people') 8 | User.all.each do |user| 9 | user.groups << group 10 | user.save! 11 | end 12 | AccessToken.create(token: 'a') 13 | 14 | vpn = Vpn.create(name: 'dev-vpn', host_name: 'dev-vpn.example.com', ip_address: '1.2.3.4', uuid: 'FC29CB92-FC7E-4F0B-B938-7612DFDECC28') 15 | HostMachine.create(name: 'SampleHost1') 16 | HostMachine.create(name: 'SampleHost2') 17 | vsd = VpnSearchDomain.create(search_domain: 'dev-search.vpn.example.com') 18 | vdns = VpnDomainNameServer.create(server_address: '8.8.8.8') 19 | vsmd = VpnSupplementalMatchDomain.create(supplemental_match_domain: 'match.domains') 20 | vpn.vpn_search_domains << vsd 21 | vpn.vpn_domain_name_servers << vdns 22 | vpn.vpn_supplemental_match_domains << vsmd 23 | vpn.save! 24 | -------------------------------------------------------------------------------- /db/seeds/production.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | # 9 | group = Group.where(name: "people").first 10 | group = Group.create(name: "people") if group.blank? 11 | 12 | group = Group.where(name: "devops").first 13 | group = Group.create(name: "devops") if group.blank? 14 | -------------------------------------------------------------------------------- /db/seeds/test.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | # 9 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | services: 3 | gate-sql: 4 | image: mysql:5.7 5 | volumes: 6 | - ${PWD}/data:/var/lib/mysql 7 | environment: 8 | - MYSQL_ALLOW_EMPTY_PASSWORD=true 9 | 10 | gate: 11 | image: gate 12 | ports: 13 | - "3000:3000" 14 | depends_on: 15 | - gate-sql 16 | env_file: 17 | - .env 18 | command: sh ./setup.sh 19 | -------------------------------------------------------------------------------- /docs/additional_setup.md: -------------------------------------------------------------------------------- 1 | # Additional Setup 2 | 3 | ### Setting-up Public Key Lookup 4 | 5 | * Ensure user has uploaded their public key into gate. 6 | * Add following lines to your sshd_config - It is located at `/etc/ssh/sshd_config` on most linux distros. 7 | 8 | ``` 9 | AuthorizedKeysCommand /usr/bin/gate_ssh.sh 10 | AuthorizedKeysCommandUser nobody 11 | ``` 12 | 13 | * Add file with following content to `/usr/bin/` with name `gate_ssh.sh` owned by root 14 | 15 | ``` 16 | #!/bin/sh 17 | /usr/bin/curl -k --silent "https:///profile/$1/key" 18 | ``` 19 | 20 | > **Please Note:** Point URL to Gate server and test by executing `gate_ssh.sh ` to see if this prints the public key. 21 | -------------------------------------------------------------------------------- /docs/administration.md: -------------------------------------------------------------------------------- 1 | # Administration 2 | 3 | ### Running Administrative Tasks 4 | 5 | You can open rails console and give one user admin privilege by setting up `user.admin = true` in console. Then when you signed-in as that user, Gate will show you its administration UI. You can do the following with Gate admin UI: 6 | 7 | * Enable/disable user account 8 | * Make user administrator 9 | * Control what host user's are allowed to login via host patterns, by default they are allowed everyhost which starts with `s-*` (we use `s-` for staging and `p-` for production) 10 | * Make user part of group, by default they are part of 'people' group. 11 | 12 | > **DNS Alert** Please note that gate rely heavily on DNS and host supplied IP addresses, so it authenticates against host native IP address rather than NAT'd IP address. It does reverse name lookup on supplied IP address, if that fails then it will be looking at matching IP address itself. 13 | 14 | ### Scheduler 15 | 16 | Gate has some tasks that can be scheduled for maintenance purpose. Please see `config/scheduler.rb` to see the list of available tasks. 17 | 18 | You can run `whenever --update-crontab` to update cronjob so that it run these tasks. Gate utilize `whenever` gem for maintaining scheduled tasks, which in turn utilize cronjob as its backend. 19 | 20 | ### Logs 21 | 22 | Logs are stored here: 23 | 24 | * Puma logs 25 | * `shared/log/puma.stdout.log` 26 | * `shared/log/puma.stderr.log` 27 | * App logs 28 | * `log/.log` 29 | 30 | Some errors may be being written directly to stdout/stderr and may not be available in the application log file. 31 | -------------------------------------------------------------------------------- /docs/dredd_setup.md: -------------------------------------------------------------------------------- 1 | # Dredd Setup 2 | 3 | Dredd is used to run test, to validate the API Blueprint against Backend Implementation. 4 | 5 | ### Install npm 6 | 7 | On Mac OS 8 | 9 | ``` 10 | brew install node 11 | ``` 12 | 13 | On Linux 14 | 15 | ``` 16 | apt-get install npm 17 | ``` 18 | 19 | ### Install dredd 20 | 21 | To install dredd globally run 22 | ``` 23 | npm install -g dredd 24 | ``` 25 | 26 | Before you run the dredd please make sure you've run the `bundler install` and fill the `env` file 27 | 28 | ### Running dredd 29 | 30 | Running without debug 31 | ``` 32 | dredd 33 | ``` 34 | 35 | Running with debug mode 36 | ``` 37 | dredd --loglevel debug 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/newrelic.md: -------------------------------------------------------------------------------- 1 | # Newrelic Integration 2 | 3 | If you want to enable Newrelic monitoring on your Gate deployment, you just need to fill these additional keys on your environment variables: 4 | 5 | ``` 6 | NEWRELIC_LICENSE_KEY - Your Newrelic license key 7 | NEWRELIC_APP_NAME - Your application name (identifer) on Newrelic 8 | NEWRELIC_AGENT_ENABLED - Set it true if you want Newrelic agent to runs 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/oauth_setup.md: -------------------------------------------------------------------------------- 1 | # OAuth Setup 2 | 3 | * Ensure that you have a registered account in Google Cloud Platform. 4 | * Enable `plus.googleapis.com` API at the following URL: 5 | 6 | https://console.developers.google.com/apis/api/plus.googleapis.com/overview?project=[YOUR-PROJECT-NAME] 7 | * Create OAuth Client ID credentials at the following URL (with type `Web Application`): 8 | 9 | https://console.developers.google.com/apis/credentials?project=[YOUR-PROJECT-NAME] 10 | * Configure Restrictions (Origins & Redirect URIs). We cannot use localhost in this section, therefore you can specify any arbitrary domain then configure your computer `/etc/hosts` file. 11 | 12 | Example if you are running on `http://example.com:4000`: 13 | * http://example.com:4000 14 | * http://example.com:4000/users/auth/google_oauth2/callback 15 | * Put client_id and client_secret on `GATE_OAUTH_CLIENT_ID` and `GATE_OAUTH_CLIENT_SECRET` respectively 16 | * Update your `GATE_SERVER_URL` to `http://example.com:4000` 17 | * Specify your e-mail domain on `GATE_HOSTED_DOMAIN` and `GATE_HOSTED_DOMAINS`, for instance if your e-mail address is `test123@gmail.com` then the value should be `gmail.com` 18 | * Leave `SIGN_IN_TYPE` empty 19 | -------------------------------------------------------------------------------- /dredd.yml: -------------------------------------------------------------------------------- 1 | color: true 2 | dry-run: null 3 | hookfiles: 'api_blueprint/hooks/dredd_hooks.rb' 4 | language: ruby 5 | require: null 6 | server: './api_blueprint/bin/dredd_server.sh' 7 | server-wait: 20 8 | init: false 9 | custom: {} 10 | names: false 11 | only: [] 12 | reporter: [] 13 | output: [] 14 | header: [] 15 | sorted: false 16 | user: null 17 | inline-errors: false 18 | details: false 19 | method: [] 20 | loglevel: warning 21 | path: [] 22 | hooks-worker-timeout: 5000 23 | hooks-worker-connect-timeout: 15000 24 | hooks-worker-connect-retry: 500 25 | hooks-worker-after-connect-wait: 100 26 | hooks-worker-term-timeout: 5000 27 | hooks-worker-term-retry: 500 28 | hooks-worker-handler-host: 127.0.0.1 29 | hooks-worker-handler-port: 61321 30 | config: ./dredd.yml 31 | blueprint: 'api_blueprint/*.apib' 32 | endpoint: 'http://localhost:9865' 33 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/app.rake: -------------------------------------------------------------------------------- 1 | namespace :app do 2 | desc "Common app related tasks" 3 | 4 | task :init do 5 | cp '.env.example', '.env' 6 | p 'Please read information @ README.md - Setting up Environment Variables' 7 | end 8 | 9 | task :setup do 10 | sh "bundle install" 11 | sh "bundle exec rake db:drop db:create db:migrate" 12 | sh "RAILS_ENV=test bundle exec rake db:migrate" 13 | sh "RAILS_ENV=test bundle exec rspec" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/tasks/setup.rake: -------------------------------------------------------------------------------- 1 | namespace :setup do 2 | desc "Setup open vpn config" 3 | 4 | task :openvpn => [:key_dir, :certificate_authority] do 5 | end 6 | 7 | task :key_dir do 8 | key_dir = Net::Openvpn::Generators::Keys::Directory.new 9 | key_dir.generate 10 | puts "#{key_dir} successfully generated" if key_dir.exist? 11 | end 12 | 13 | task :certificate_authority do 14 | ca = Net::Openvpn::Generators::Keys::Authority.new 15 | ca.generate 16 | ca.exist? 17 | puts "#{ca} successfully generated" if ca.exist? 18 | end 19 | 20 | task :server do 21 | keys = Net::Openvpn::Generators::Keys::Server.new("swzvpn04") 22 | keys.generate 23 | keys.exist? 24 | keys.valid? 25 | end 26 | 27 | # example rake setup:client['ajey'] 28 | task :client , [:name] => :environment do |task, args| 29 | puts "generating key for #{args.name}" 30 | keys = Net::Openvpn::Generators::Keys::Client.new(args.name) 31 | keys.generate 32 | keys.exist? 33 | keys.valid? 34 | puts "key for #{args.name} successfully generated" if keys.valid? 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/tasks/vpn.rake: -------------------------------------------------------------------------------- 1 | namespace :users do 2 | 3 | desc "migrate vpn user from old group to new groups" 4 | task migrate_vpns: :environment do 5 | 6 | vpns = Vpn.all 7 | 8 | vpns.each do |vpn| 9 | admin_groups = vpn.groups 10 | #create a new group for VPN 11 | group = Group.create(name: "#{vpn.name}_access_group", description: "VPN Access group") 12 | #Assign VPN to group 13 | #get all vpn administrators 14 | admins = [] 15 | admin_groups.each do |admin_group| 16 | admin_group.group_admins.each do |group_admin| 17 | admins << group_admin.user 18 | end 19 | end 20 | 21 | #add all vpn administrators to new group as admin 22 | admins.each do |user| 23 | group.add_admin user 24 | end 25 | #get all vpn users 26 | #add all vpn users to new group 27 | vpn.users.each do |user| 28 | user.groups << group 29 | end 30 | group.save! 31 | 32 | @vpn.groups << group 33 | end 34 | end 35 | end 36 | 37 | -------------------------------------------------------------------------------- /lib/vpn/mobileconfig.rb: -------------------------------------------------------------------------------- 1 | require 'erb' 2 | require 'vpn/namespace' 3 | require 'openssl' 4 | 5 | class Mobileconfig 6 | def generate (vpns, user) 7 | mobileconfig_template = File.read("#{Rails.root}/lib/vpn/mobileconfig.erb") 8 | 9 | vpn_hash = [] 10 | vpns.each do |vpn| 11 | vpn_hash << { 12 | "payload_identifier" => "#{vpn.host_name.split('.').reverse.join('.')}.conf", 13 | "payload_uuid" => vpn.uuid, 14 | "user_defined_name" => vpn.name, 15 | "ikev2" => { 16 | "remote_address" => vpn.host_name, 17 | "remote_identifier" => vpn.host_name, 18 | "auth_name" => user.email.split('@').first 19 | }, 20 | "dns" => { 21 | "server_addresses" => vpn.vpn_domain_name_servers.collect{ |vdns| vdns.server_address }, 22 | "search_domains" => vpn.vpn_search_domains.collect{ |vsd| vsd.search_domain }, 23 | "supplemental_match_domains" => vpn.vpn_supplemental_match_domains.collect{ |vsmd| vsmd.supplemental_match_domain }, 24 | } 25 | } 26 | end 27 | 28 | confighash = { 29 | organization_name: ENV['GATE_ORGANIZATION_NAME'] + ' IKEv2 VPN Configuration', 30 | reverse_vpn_url: ENV['GATE_SERVER_URL'].split('.').reverse.join('.'), 31 | organization_static: ENV['GATE_ORGANIZATION_STATIC'], 32 | payload_content: vpn_hash, 33 | } 34 | 35 | namespace = Namespace.new(confighash) 36 | 37 | mobileconfig_unsigned = ERB.new(mobileconfig_template).result(namespace.get_binding) 38 | 39 | sign_mobileconfig(mobileconfig_unsigned) 40 | end 41 | 42 | private 43 | 44 | def sign_mobileconfig(mobileconfig) 45 | private_key = Base64.decode64(ENV['GATE_VPN_SSL_PVTKEY']) 46 | signing_cert = Base64.decode64(ENV['GATE_VPN_SSL_CERT']) 47 | cross_signed_cert = Base64.decode64(ENV['GATE_VPN_SSL_XSIGNED']) 48 | 49 | key = OpenSSL::PKey::RSA.new private_key 50 | cert = OpenSSL::X509::Certificate.new signing_cert 51 | cross_signed = OpenSSL::X509::Certificate.new cross_signed_cert 52 | 53 | OpenSSL::PKCS7.sign(cert, key, mobileconfig, [cross_signed]).to_der 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/vpn/namespace.rb: -------------------------------------------------------------------------------- 1 | class Namespace 2 | def initialize(hash) 3 | hash.each do |key, value| 4 | singleton_class.send(:define_method, key) { value } 5 | end 6 | end 7 | def get_binding 8 | binding 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /node_modules/.yarn-integrity: -------------------------------------------------------------------------------- 1 | { 2 | "systemParams": "darwin-arm64-108", 3 | "modulesFolders": [], 4 | "flags": [], 5 | "linkedModules": [], 6 | "topLevelPatterns": [], 7 | "lockfileEntries": {}, 8 | "files": [], 9 | "artifacts": {} 10 | } -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

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

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

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

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | User-agent: * 5 | Disallow: / 6 | -------------------------------------------------------------------------------- /scripts/gen-client-conf: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $# -lt 1 ]]; then 4 | echo "$0 " 5 | exit 1 6 | fi 7 | 8 | cd /etc/openvpn/keys 9 | cp /opt/vpnkeys/$1.tar.gz ./ 10 | tar -xf $1.tar.gz 11 | rm $1.ovpn 12 | touch $1.ovpn 13 | 14 | cat > /etc/openvpn/keys/$1.ovpn <> 1194 19 | resolv-retry infinite 20 | nobind 21 | persist-key 22 | persist-tun 23 | ca ca.crt 24 | cert $1.crt 25 | key $1.key 26 | comp-lzo 27 | verb 3 28 | auth-user-pass 29 | auth-nocache 30 | tun-mtu 1400 31 | mssfix 1400 32 | 33 | #add your routes here 34 | route <> 35 | route <> 36 | EOF 37 | 38 | tar zcf $1.tar.gz ca.crt $1.crt $1.key $1.ovpn 39 | chmod 0600 $1.tar.gz 40 | 41 | mkdir -p /opt/vpnkeys/ 42 | cp $1.tar.gz /opt/vpnkeys/ 43 | rm $1.* 44 | -------------------------------------------------------------------------------- /scripts/gen-client-keys: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [[ $# -lt 1 ]]; then 6 | echo "$0 " 7 | exit 1 8 | fi 9 | 10 | source vars 11 | 12 | touch /etc/openvpn/keys/$1.ovpn 13 | 14 | cat > /etc/openvpn/keys/$1.ovpn <> 1194 19 | resolv-retry infinite 20 | nobind 21 | persist-key 22 | persist-tun 23 | ca ca.crt 24 | cert $1.crt 25 | key $1.key 26 | comp-lzo 27 | verb 3 28 | auth-user-pass 29 | auth-nocache 30 | tun-mtu 1400 31 | mssfix 1400 32 | #Add your routes 33 | route <> 34 | route <> 35 | EOF 36 | 37 | ./pkitool $1 38 | cd /etc/openvpn/keys/ && tar zcf $1.tar.gz ca.crt $1.crt $1.key $1.ovpn 39 | chmod 0600 $1.tar.gz 40 | 41 | mkdir -p /opt/vpnkeys/ 42 | cp $1.tar.gz /opt/vpnkeys/ 43 | rm $1.* 44 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | rake db:setup && rails s 2 | -------------------------------------------------------------------------------- /spec/controllers/admin_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe AdminController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/api/v1/api_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ::Api::V1::BaseController, type: :controller do 4 | 5 | controller(::Api::V1::BaseController) do 6 | def index 7 | head :ok 8 | end 9 | end 10 | 11 | describe 'Authentication' do 12 | before(:each) do 13 | @user = build(:user) 14 | @user.access_token = build(:access_token) 15 | @user.save 16 | @token = @user.access_token.token 17 | end 18 | it 'gives 200 when access token is valid' do 19 | get :index, params: { access_token: @token } 20 | expect(response.status).to eq(200) 21 | end 22 | 23 | it 'gives 401 when access token is in valid' do 24 | get :index, params: { access_token: "foo" } 25 | expect(response.status).to eq(401) 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/controllers/api/v1/vpns_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ::Api::V1::VpnsController, type: :controller do 4 | let(:valid_attributes) { 5 | {name: 'jumbo'} 6 | } 7 | 8 | before(:each) do 9 | @user = build(:user) 10 | @user.access_token = build(:access_token) 11 | @user.save 12 | @token = @user.access_token.token 13 | end 14 | 15 | describe 'Authenticated' do 16 | describe 'Create Vpn' do 17 | context 'with valid_attributes' do 18 | it 'should create vpns' do 19 | post :create, params: {vpn: valid_attributes, access_token: @token} 20 | vpn = Vpn.where(name: valid_attributes[:name]).first 21 | expect(vpn.blank?).to eq(false) 22 | expect(vpn.name).to eq(valid_attributes[:name]) 23 | expect(UUID.validate(vpn.uuid)).to eq(true) 24 | end 25 | 26 | it 'should return proper response' do 27 | post :create, params: {vpn: valid_attributes, access_token: @token} 28 | expect(response.status).to eq(200) 29 | vpn = Vpn.where(name: valid_attributes[:name]).first 30 | obj = JSON.parse(response.body) 31 | expect(obj['id']).to eq vpn.id 32 | expect(obj['name']).to eq vpn.name 33 | expect(obj['host_name']).to eq vpn.host_name 34 | expect(obj['ip_address']).to eq vpn.ip_address 35 | end 36 | end 37 | end 38 | 39 | describe 'Assign Group to VPN' do 40 | it 'should replace existing vpn group with new group' do 41 | vpn = create(:vpn) 42 | group_1 = create(:group) 43 | group_2 = create(:group) 44 | vpn.groups << group_1 45 | vpn.groups << group_2 46 | group_3 = create(:group) 47 | post :assign_group, params: {access_token: @token, id: vpn.id, group_id: group_3.id} 48 | expect(vpn.groups.count).to eq 1 49 | expect(vpn.groups.first).to eq group_3 50 | end 51 | end 52 | end 53 | 54 | describe 'Unauthenticated' do 55 | it 'gives 401 when access token is invalid' do 56 | post :create, params: {vpn: valid_attributes, access_token: 'foo'} 57 | expect(response.status).to eq(401) 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/controllers/home_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe HomeController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/host_machine_groups_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe HostMachineGroupsController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/omniauth_callbacks_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Users::OmniauthCallbacksController, type: :controller do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /spec/controllers/profile_controller_spec.rb: -------------------------------------------------------------------------------- 1 | describe ProfileController, type: :controller do 2 | let!(:admin) { create(:admin_user) } 3 | let(:user) { create(:user, admin: false) } 4 | 5 | describe '#update' do 6 | context 'unauthenticated' do 7 | it 'should return status 302' do 8 | post :update, params: { id: user.id } 9 | 10 | expect(response).to have_http_status(302) 11 | end 12 | end 13 | 14 | context 'authenticated as admin' do 15 | it 'should update user' do 16 | new_user = create(:user, active: true, admin: true) 17 | sign_in admin 18 | 19 | post :update, params: { id: new_user.id, user: { admin: false, active: false } } 20 | new_user.reload 21 | 22 | expect(new_user).to have_attributes(active: false, admin: false) 23 | end 24 | 25 | it 'should revoke admin when deactivate user' do 26 | new_user = create(:user, active: true, admin: true) 27 | sign_in admin 28 | 29 | post :update, params: { id: new_user.id, user: { active: false } } 30 | new_user.reload 31 | 32 | expect(new_user).to have_attributes(active: false, admin: false) 33 | end 34 | 35 | it 'should redirect to user_path after update' do 36 | sign_in admin 37 | 38 | post :update, params: { id: user.id, user: { admin: false, active: false } } 39 | 40 | expect(response).to redirect_to(user_path) 41 | end 42 | end 43 | 44 | context 'authenticated as non admin' do 45 | it 'should not update user' do 46 | new_user = create(:user, active: true, admin: true) 47 | sign_in user 48 | 49 | post :update, params: { id: new_user.id, user: { admin: false, active: false } } 50 | new_user.reload 51 | 52 | expect(new_user).to have_attributes(active: true, admin: true) 53 | end 54 | end 55 | end 56 | 57 | describe '#download_vpn_for_ios_and_mac' do 58 | context "user doesn't have vpn" do 59 | it 'should return status 200' do 60 | sign_in user 61 | 62 | get :download_vpn_for_ios_and_mac 63 | 64 | expect(response).to have_http_status(200) 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/controllers/users/auth_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Users::AuthController, type: :controller do 4 | let(:user) { FactoryBot.create(:user, name: 'foobar', email: 'foobar@foobar.com') } 5 | 6 | context 'sign in' do 7 | before(:each) do 8 | @cached_domain_env = ENV['GATE_HOSTED_DOMAINS'] 9 | @cached_sign_in_type = ENV['SIGN_IN_TYPE'] 10 | ENV['GATE_HOSTED_DOMAINS'] = 'foobar.com' 11 | ENV['SIGN_IN_TYPE'] = 'form' 12 | end 13 | 14 | after(:each) do 15 | ENV['GATE_HOSTED_DOMAINS'] = @cached_domain_env 16 | ENV['SIGN_IN_TYPE'] = @cached_sign_in_type 17 | end 18 | 19 | it 'should redirect to home when success' do 20 | post :log_in, params: { name: user.name, email: user.email } 21 | 22 | expect(response).to redirect_to(root_path) 23 | end 24 | 25 | it 'should produce error and unauthorized status when email domain is unsupported' do 26 | post :log_in, params: { name: user.name, email: 'foobar@notfoobar.com' } 27 | 28 | expect(response).to have_http_status(401) 29 | expect(response.body).to eq('Your domain is unauthorized') 30 | end 31 | 32 | it 'should generate two factor auth when success' do 33 | post :log_in, params: { name: user.name, email: user.email } 34 | 35 | user.reload 36 | expect(user.auth_key).not_to be_nil 37 | end 38 | 39 | it 'should set user session when success' do 40 | post :log_in, params: { name: user.name, email: user.email } 41 | 42 | expect(subject.current_user).to eq(user) 43 | end 44 | 45 | it 'should redirect to home when sign in type is not form' do 46 | ENV['SIGN_IN_TYPE'] = 'not_form' 47 | 48 | post :log_in, params: { name: user.name, email: user.email } 49 | 50 | expect(response).to redirect_to(root_path) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/factories/access_tokens.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :access_token do 3 | token { SecureRandom.uuid } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/api_resources.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :api_resource do 3 | sequence(:name, 1000) { |n| "API#{n}" } 4 | description { "MyString" } 5 | access_key { "MyString" } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/endpoints.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :endpoint do 3 | path { '/' } 4 | add_attribute(:method) { ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].sample } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/group_associations.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :group_association do 3 | user { "" } 4 | group { "" } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/groups.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :group do 3 | sequence(:name, 1000) { |n| "People#{n}" } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/host_access_groups.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :host_access_group do 3 | references { "" } 4 | references { "" } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/host_machine_groups.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :host_machine_group do 3 | user { nil } 4 | host_machine { nil } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/host_machines.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :host_machine do 3 | sequence(:name) { |n| "host-#{n}" } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/factories/ip_addresses.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :ip_address do 3 | address { "MyString" } 4 | mac_address { "MyString" } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/organisations.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | #country = Country.find_country_by_name(Country.all.map(&:name).sort.sample) 3 | factory :organisation do 4 | sequence(:slug) { |n| "#{Faker::Lorem.word}_#{n}" } 5 | name { Faker::Lorem.word } 6 | website { Faker::Internet.url } 7 | domain { Faker::Internet.email.split('@').last } 8 | country { country.gec } 9 | state { Faker::Address.state } 10 | address { Faker::Lorem.words(number: 3).join(' ') } 11 | unit_name { 'IT' } 12 | admin_email_address { Faker::Internet.email } 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/factories/saml_app_configs.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :saml_app_config do 3 | sso_url { Faker::Internet.url } 4 | group { create(:group, name: "saml_#{Faker::Lorem.word}_datadog_users") } 5 | config { { app_key: Faker::Internet.password(min_length: 8), api_key: Faker::Internet.password(min_length: 8) } } 6 | organisation { build(:organisation) } 7 | app_name { 'datadog' } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/user_host_access_groups.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :user_host_access_group do 3 | user { nil } 4 | host_access_group { nil } 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/vpns.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :vpn do 3 | sequence(:name) { |n| "VPN#{n}" } 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /spec/features/layout_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Layout', type: :feature do 3 | let(:user) { create(:user) } 4 | let(:group_admin) { create(:group_admin) } 5 | let(:admin) { create(:admin_user) } 6 | scenario 'Access to user links' do 7 | sign_in(user) 8 | visit profile_path 9 | links = { 10 | 'APIs' => api_resources_path, 11 | 'VPNs' => vpns_path, 12 | 'API' => new_api_resource_path, 13 | } 14 | links.each do |link_text, link_href| 15 | expect(page).to have_xpath( 16 | "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" 17 | ) 18 | end 19 | end 20 | scenario 'Access to group admin links' do 21 | sign_in(group_admin) 22 | visit profile_path 23 | links = { 24 | 'APIs' => api_resources_path, 25 | 'Groups' => groups_path, 26 | 'VPNs' => vpns_path, 27 | 'API' => new_api_resource_path, 28 | } 29 | links.each do |link_text, link_href| 30 | expect(page).to have_xpath( 31 | "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" 32 | ) 33 | end 34 | end 35 | scenario 'Access to admin links' do 36 | sign_in(admin) 37 | visit root_path 38 | links = { 39 | 'Users' => users_path, 40 | 'Hosts' => host_machines_path, 41 | 'Organisations' => organisations_path, 42 | 'Groups' => groups_path, 43 | 'APIs' => api_resources_path, 44 | 'VPNs' => vpns_path, 45 | 'API' => new_api_resource_path, 46 | 'Group' => new_group_path, 47 | 'VPN' => new_vpn_path, 48 | 'Organisation' => new_organisation_path, 49 | } 50 | links.each do |link_text, link_href| 51 | expect(page).to have_xpath( 52 | "//div[@id='main-navigation']//a[@href='#{link_href}' and .='#{link_text}']" 53 | ) 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/features/organisations/add_user_saml_app_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Config Saml App', type: :feature do 3 | let(:user) { create(:user) } 4 | let(:users) { create_list(:user, 10) } 5 | let(:org) { create(:organisation) } 6 | 7 | before do 8 | sign_in(user) 9 | end 10 | 11 | scenario 'Add user to group' do 12 | create( 13 | :saml_app_config, 14 | organisation: org, 15 | group: Group.new(name: "#{org.slug}_saml_datadog_users") 16 | ) 17 | allow_any_instance_of(Group).to receive(:users).and_return(users) 18 | home_path = organisation_config_saml_app_path( 19 | organisation_id: org.id, app_name: 'datadog' 20 | ) 21 | visit home_path 22 | page.find('#manage-users-tab').click 23 | page.find_field('email').set(user.email) 24 | expect_any_instance_of(Datadog). 25 | to receive(:add_user).with(user.email) 26 | page.find('#add_user_to_app').click 27 | expect(current_path).to eq(home_path) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/features/organisations/create_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Create Organisation', type: :feature do 3 | let(:org_data) { attributes_for(:organisation) } 4 | let(:user) { create(:user) } 5 | scenario 'Create an organisation successfully' do 6 | sign_in(user) 7 | visit new_organisation_path 8 | select Country.all.sample.name, from: 'organisation_country' 9 | %w(name website domain state address admin_email_address slug unit_name).each do |key| 10 | fill_in "organisation_#{key}", with: org_data[key.to_sym] 11 | end 12 | click_button('Create Organisation') 13 | expect(current_path).to eq(organisations_path) 14 | expect(page).to have_xpath( 15 | "//div[@id='organisation_form_success' and .='Successfully created organisation']" 16 | ) 17 | end 18 | scenario 'Display Errors on Creating Organisation' do 19 | sign_in(user) 20 | visit new_organisation_path 21 | fill_in 'organisation_name', with: org_data[:name] 22 | click_button('Create Organisation') 23 | expect(current_path).to eq(organisations_path) 24 | expect(page).to have_xpath( 25 | "//div[@id='organisation_form_errors']" 26 | ) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/features/organisations/list_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'List Organisations', type: :feature do 3 | let!(:orgs) { create_list(:organisation, 5) } 4 | let(:user) { create(:user) } 5 | scenario 'Can create an organisation' do 6 | sign_in(user) 7 | visit organisations_path 8 | expect(page).to have_xpath("//a[@id='new_organisation_btn']") 9 | end 10 | scenario 'View list of organisations' do 11 | sign_in(user) 12 | visit organisations_path 13 | table_xpath = "//div[@id='organisation_list']/table" 14 | orgs.each do |org| 15 | expect(page).to have_xpath( 16 | "#{table_xpath}//td/a[@href='#{organisation_path(org)}' and .='#{org.name}']" 17 | ) 18 | expect(page).to have_xpath( 19 | "#{table_xpath}//td/a[@href='#{org.website}' and .='#{org.website}']" 20 | ) 21 | expect(page).to have_xpath( 22 | "#{table_xpath}//td[.='#{org.domain}']" 23 | ) 24 | expect(page).to have_xpath( 25 | "#{table_xpath}//td/a[@href='#{organisation_setup_saml_path(org)}' and .='Setup SAML']" 26 | ) 27 | end 28 | end 29 | scenario 'Ability to see organsiation details' do 30 | sign_in(user) 31 | visit organisations_path 32 | table_xpath = "//div[@id='organisation_list']/table" 33 | orgs.each do |org| 34 | expect(page).to have_xpath( 35 | "#{table_xpath}//td/a[@href='#{organisation_path(org)}' and .='#{org.name}']" 36 | ) 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/features/organisations/remove_user_saml_app_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Config Saml App', type: :feature do 3 | let(:user) { create(:user) } 4 | let(:users) { create_list(:user, 10) } 5 | let(:org) { create(:organisation) } 6 | 7 | before do 8 | sign_in(user) 9 | end 10 | 11 | scenario 'Remove user from group' do 12 | create( 13 | :saml_app_config, 14 | organisation: org, 15 | group: Group.new(name: "#{org.slug}_saml_datadog_users") 16 | ) 17 | allow_any_instance_of(Group).to receive(:users).and_return(users) 18 | home_path = organisation_config_saml_app_path( 19 | organisation_id: org.id, app_name: 'datadog' 20 | ) 21 | visit home_path 22 | page.find('#manage-users-tab').click 23 | expect_any_instance_of(Datadog). 24 | to receive(:remove_user).with(users.first.email) 25 | page.find("#saml_user_remove_#{users.first.id}").click 26 | expect(current_path).to eq(home_path) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /spec/features/organisations/save_config_saml_app_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Save Config Saml App', type: :feature do 3 | let(:org) { create(:organisation) } 4 | let(:user) { create(:user) } 5 | let(:app_name) { 'datadog' } 6 | 7 | before do 8 | sign_in(user) 9 | end 10 | 11 | scenario 'Load Present Configuration' do 12 | url = Faker::Internet.url 13 | saml_app = Datadog.new(org.id) 14 | app_key = Faker::Internet.password(min_length: 8) 15 | api_key = Faker::Internet.password(min_length: 8) 16 | saml_app.save_config(url, app_key: app_key, api_key: api_key) 17 | visit organisation_config_saml_app_path( 18 | organisation_id: org.id, app_name: app_name 19 | ) 20 | page.find('#settings-tab').click 21 | expect(page.find_field('saml_app_config_sso_url').value).to eq(url) 22 | expect(page.find_field('config_app_key').value).to eq(app_key) 23 | expect(page.find_field('config_api_key').value).to eq(api_key) 24 | end 25 | 26 | scenario 'Load New Configuration If Not Saved' do 27 | visit organisation_config_saml_app_path( 28 | organisation_id: org.id, app_name: app_name 29 | ) 30 | page.find('#settings-tab').click 31 | expect(page.find_field('saml_app_config_sso_url').value.blank?).to eq(true) 32 | expect(page.find_field('config_app_key').value.blank?).to eq(true) 33 | expect(page.find_field('config_api_key').value.blank?).to eq(true) 34 | end 35 | 36 | scenario 'Save Configuration' do 37 | url = Faker::Internet.url 38 | app_key = Faker::Internet.password(min_length: 8) 39 | api_key = Faker::Internet.password(min_length: 8) 40 | path = organisation_config_saml_app_path( 41 | organisation_id: org.id, app_name: app_name 42 | ) 43 | visit path 44 | page.find('#settings-tab').click 45 | page.find_field('saml_app_config_sso_url').set(url) 46 | page.find_field('config_app_key').set(app_key) 47 | page.find_field('config_api_key').set(api_key) 48 | page.find('#new_saml_app_config').click 49 | expect(current_path).to eq(path) 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/features/organisations/setup_saml_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Setup SAML', type: :feature do 3 | let!(:org) { create(:organisation) } 4 | let(:user) { create(:user) } 5 | scenario 'Should show a success message if SAML is setup' do 6 | sign_in(user) 7 | allow_any_instance_of(Organisation).to receive(:setup_saml_certs).and_return(true) 8 | visit organisation_setup_saml_path(org) 9 | expect(current_path).to eq(organisations_path) 10 | expect(page).to have_xpath( 11 | "//div[@id='organisation_form_success' and .='Successfully setup SAML Certificates']" 12 | ) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/features/organisations/update_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Update Organisation', type: :feature do 3 | let!(:org) { create(:organisation) } 4 | let(:org_data) { attributes_for(:organisation) } 5 | let(:user) { create(:user) } 6 | scenario 'Create an organisation successfully' do 7 | sign_in(user) 8 | visit organisation_path(org) 9 | select Country.all.sample.name, from: 'organisation_country' 10 | %w(name website domain state address admin_email_address slug unit_name).each do |key| 11 | fill_in "organisation_#{key}", with: org_data[key.to_sym] 12 | end 13 | click_button('Update Organisation') 14 | expect(current_path).to eq(organisations_path) 15 | expect(page).to have_xpath( 16 | "//div[@id='organisation_form_success' and .='Successfully updated organisation']" 17 | ) 18 | end 19 | scenario 'Display Errors on Creating Organisation' do 20 | sign_in(user) 21 | visit organisation_path(org) 22 | fill_in 'organisation_name', with: '' 23 | click_button('Update Organisation') 24 | expect(current_path).to eq(organisation_path(org)) 25 | expect(page).to have_xpath( 26 | "//div[@id='organisation_form_errors']" 27 | ) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/features/saml/show_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Config Saml App', type: :feature do 3 | let(:org) { create(:organisation) } 4 | let(:user) { create(:user) } 5 | let(:saml_apps) { ENV['SAML_APPS'].split(',') } 6 | let(:xml_content) { Nokogiri::XML::Builder.new { |xml| xml.foo_bar 'hello' }.to_xml } 7 | 8 | before do 9 | sign_in(user) 10 | allow(SamlIdp.metadata).to receive(:signed).and_return(xml_content) 11 | end 12 | 13 | scenario 'Show metadata when no download flag' do 14 | visit metadata_path(slug: org.slug, app: saml_apps.sample) 15 | expect(page.body).to eq(xml_content) 16 | end 17 | 18 | scenario 'Download metadata with download flag' do 19 | visit metadata_path(slug: org.slug, app: saml_apps.sample, download: true) 20 | expect(page.response_headers['Content-Type']).to eq('text/xml') 21 | expect(page.response_headers['Content-Disposition']).to include('metadata.xml') 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/features/users/regenerate_auth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | RSpec.feature 'Rengenerate Auth Token', type: :feature do 3 | let(:user) { create(:user) } 4 | let(:rotp_key) { ROTP::Base32.random_base32 } 5 | before(:each) do 6 | allow(ROTP::Base32).to receive(:random_base32).and_return(rotp_key) 7 | end 8 | scenario 'Create an organisation successfully' do 9 | sign_in user 10 | expect(user).to receive(:generate_two_factor_auth).with(true) 11 | visit regenerate_authentication_path 12 | expect(current_path).to eq(profile_path) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/helpers/application_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe ApplicationHelper, type: :helper do 4 | describe '.add_placeholder_to_list' do 5 | let (:placeholder) { 'placeholder' } 6 | let(:list) { (1..5).map { |ix| "row#{ix}" } } 7 | 8 | it 'returns list with first element of every array titleized and adds placeholder' do 9 | titleized_list = list.map { |row| [row.titleize, row] }.insert(0, [placeholder, '']) 10 | expect(helper.add_placeholder_to_list(list, placeholder)).to eq(titleized_list) 11 | end 12 | 13 | it 'returns list with first element of every array with string function and adds placeholder' do 14 | titleized_list = list.map { |row| [row.capitalize, row] }.insert(0, [placeholder, '']) 15 | expect(helper.add_placeholder_to_list(list, placeholder, string_convert: 'capitalize')).to eq(titleized_list) 16 | end 17 | 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/lib/tasks/users_rake_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe "users:purge_inactive" do 4 | before(:each) do 5 | create(:user) 6 | @user = create(:user) 7 | @user.update!(active: false) 8 | end 9 | 10 | it "purge users whom have been deactivated for more than certain time" do 11 | Gate::Application.load_tasks 12 | @user.update_column(:deactivated_at, Time.now - 16.days) 13 | Rake::Task['users:purge_inactive'].invoke 14 | @user.reload 15 | expect(@user.group_associations.length).to eq 0 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/models/access_token_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe AccessToken, type: :model do 4 | let(:user) { 5 | FactoryBot.create(:user, 6 | name: "foobar", 7 | admin: true, 8 | user_login_id: "foobar", 9 | email: "foobar@foobar.com" 10 | ) 11 | } 12 | 13 | before(:each) do 14 | @access_token = AccessToken.new 15 | @access_token.token = ROTP::Base32.random_base32 16 | @access_token.user = user 17 | @access_token.save! 18 | end 19 | 20 | describe "self.find_token" do 21 | it "should return access token object if it finds matching token" do 22 | expect(AccessToken.find_token(@access_token.token)).to eq @access_token 23 | end 24 | end 25 | 26 | describe "self.valid_token" do 27 | it "should return true if it finds matching token" do 28 | expect(AccessToken.valid_token(@access_token.token)).to eq true 29 | end 30 | end 31 | 32 | describe "hash_token! before_save" do 33 | it "should hash token and put it into hashed_token" do 34 | expect(@access_token.hashed_token).to eq( 35 | Digest::SHA512.hexdigest(@access_token.token)) 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/models/api_resource_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe ApiResource, type: :model do 4 | let(:user) { 5 | FactoryBot.create(:user, 6 | name: "foobar", 7 | admin: true, 8 | user_login_id: "foobar", 9 | email: "foobar@foobar.com" 10 | ) 11 | } 12 | let(:group) { FactoryBot.create(:group, name: "foobar_group") } 13 | let(:valid_attributes) do 14 | { 15 | name: "sample_api", 16 | description: "sample_api_description", 17 | access_key: "xcz", 18 | user_id: user.id, 19 | group_id: group.id 20 | } 21 | end 22 | 23 | describe "self.authenticate" do 24 | it "should return true if it finds matching access_key and the user is member of the group" do 25 | api_resource = ApiResource.create(valid_attributes) 26 | group.users << user 27 | access_token = AccessToken.new 28 | access_token.token = ROTP::Base32.random_base32 29 | access_token.user = user 30 | access_token.save! 31 | expect(ApiResource.authenticate(valid_attributes[:access_key], access_token.token)).to eq true 32 | end 33 | end 34 | 35 | describe "hash_access_key! before_save" do 36 | it "should hash access_key and put it into hashed_access_key" do 37 | api_resource = ApiResource.create(valid_attributes) 38 | expect(api_resource.hashed_access_key).to eq( 39 | Digest::SHA512.hexdigest(valid_attributes[:access_key])) 40 | end 41 | 42 | it "shouldn't change hashed_access_key if access_key isn't supplied" do 43 | api_resource = ApiResource.create(valid_attributes) 44 | api_resource.update(description: "Change Description") 45 | expect(api_resource.hashed_access_key).to eq( 46 | Digest::SHA512.hexdigest(valid_attributes[:access_key])) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/models/endpoint_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe Endpoint, type: :model do 4 | describe 'validations' do 5 | describe 'path' do 6 | context 'when given nil path' do 7 | it 'should not valid' do 8 | endpoint = build(:endpoint, path: nil) 9 | expect(endpoint).not_to be_valid 10 | end 11 | end 12 | 13 | context 'when given path with parameter' do 14 | it 'should valid' do 15 | endpoint = build(:endpoint, path: '/users/:id') 16 | expect(endpoint).to be_valid 17 | end 18 | end 19 | 20 | context 'when given invalid path' do 21 | it 'should not valid' do 22 | endpoint = build(:endpoint, path: '/users/::id') 23 | expect(endpoint).not_to be_valid 24 | end 25 | end 26 | 27 | context 'when given path ended with /' do 28 | it 'should not valid' do 29 | endpoint = build(:endpoint, path: '/users/') 30 | expect(endpoint).not_to be_valid 31 | end 32 | end 33 | end 34 | 35 | describe 'method' do 36 | context 'when given nil method' do 37 | it 'should not valid' do 38 | endpoint = build(:endpoint, method: nil) 39 | expect(endpoint).not_to be_valid 40 | end 41 | end 42 | 43 | context 'when given unknown method' do 44 | it 'should not valid' do 45 | endpoint = build(:endpoint, method: 'JUMP') 46 | expect(endpoint).not_to be_valid 47 | end 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /spec/models/group_association_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe GroupAssociation, type: :model do 4 | describe '.revoke_expired' do 5 | let(:user) { create(:user) } 6 | let(:group) { create(:group) } 7 | 8 | context 'when found expired associations' do 9 | it 'should revoke associations' do 10 | group.add_user_with_expiration(user, Date.today - 1) 11 | 12 | GroupAssociation.revoke_expired 13 | 14 | expired_association = GroupAssociation.where('expiration_date < ?', Date.today).count 15 | expect(expired_association).to eq 0 16 | end 17 | 18 | it 'should create paper trail with event destroy' do 19 | group_association = group.add_user_with_expiration(user, Date.today - 1) 20 | 21 | GroupAssociation.revoke_expired 22 | 23 | versions = PaperTrail::Version. 24 | with_item_keys(GroupAssociation.name, group_association.id). 25 | where(event: 'destroy') 26 | expect(versions.length).to eq(1) 27 | end 28 | end 29 | 30 | it 'should not revoke associations that not expired yet' do 31 | group.add_user_with_expiration(user, Date.today) 32 | 33 | GroupAssociation.revoke_expired 34 | 35 | unexpired_association = GroupAssociation.where('expiration_date >= ?', Date.today).count 36 | expect(unexpired_association).to eq 1 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/models/group_endpoint_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | describe GroupEndpoint, type: :model do 4 | let(:group) { create(:group) } 5 | let(:endpoint) { create(:endpoint) } 6 | 7 | describe 'validations' do 8 | context 'given duplicate group with endpoint' do 9 | it 'should not valid' do 10 | GroupEndpoint.create(group: group, endpoint: endpoint) 11 | group_endpoint = GroupEndpoint.new(group: group, endpoint: endpoint) 12 | expect(group_endpoint).not_to be_valid 13 | end 14 | end 15 | 16 | context 'given nil group' do 17 | it 'should not valid' do 18 | group_endpoint = GroupEndpoint.new(group: nil, endpoint: endpoint) 19 | expect(group_endpoint).not_to be_valid 20 | end 21 | end 22 | 23 | context 'given nil endpoint' do 24 | it 'should not valid' do 25 | group_endpoint = GroupEndpoint.new(group: group, endpoint: nil) 26 | expect(group_endpoint).not_to be_valid 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/models/host_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Host, type: :model do 4 | end 5 | -------------------------------------------------------------------------------- /spec/models/ip_address_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe IpAddress, type: :model do 4 | end 5 | -------------------------------------------------------------------------------- /spec/models/vpn_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe Vpn, type: :model do 4 | context "vpn administration" do 5 | it "should test user and vpn management" do 6 | vpn = Vpn.create(name: "X") 7 | group = create(:group) 8 | vpn.groups << group 9 | vpn.save! 10 | 11 | user = create(:user) 12 | 13 | group.users << user 14 | group.save! 15 | 16 | expect(Vpn.administrator? user).to eq false 17 | 18 | group.add_admin user 19 | 20 | expect(Vpn.administrator? user).to eq true 21 | expect(Vpn.managed_vpns(user).count).to eq 1 22 | vpn = Vpn.create(name: :"Y") 23 | vpn.groups << group 24 | vpn.save! 25 | expect(Vpn.managed_vpns(user).count).to eq 2 26 | vpn = Vpn.create(name: :"Z") 27 | expect(Vpn.managed_vpns(user).count).to eq 2 28 | vpn = Vpn.create(name: :"Z1") 29 | group = create(:group) 30 | vpn.groups << group 31 | vpn.save! 32 | expect(Vpn.managed_vpns(user).count).to eq 2 33 | group.users << user 34 | group.save! 35 | group.add_admin user 36 | expect(Vpn.managed_vpns(user).count).to eq 3 37 | end 38 | 39 | it "should list all vpns for given user" do 40 | 41 | 42 | vpn = Vpn.create(name: :"X") 43 | group = create(:group) 44 | vpn.groups << group 45 | vpn.save! 46 | 47 | user = create(:user) 48 | 49 | if !group.member? user 50 | group.users << user 51 | group.save! 52 | end 53 | 54 | expect(Vpn.user_vpns(user).count).to eq 1 55 | vpn = Vpn.create(name: :"Y") 56 | vpn.groups << group 57 | vpn.save! 58 | expect(Vpn.user_vpns(user).count).to eq 2 59 | vpn = Vpn.create(name: :"Z") 60 | expect(Vpn.user_vpns(user).count).to eq 2 61 | vpn = Vpn.create(name: :"Z1") 62 | group = create(:group) 63 | group.users << user 64 | vpn.groups << group 65 | vpn.save! 66 | expect(Vpn.user_vpns(user).count).to eq 3 67 | 68 | 69 | end 70 | end 71 | end 72 | 73 | -------------------------------------------------------------------------------- /spec/routing/api_resources_routing_spec.rb: -------------------------------------------------------------------------------- 1 | require "rails_helper" 2 | 3 | RSpec.describe ApiResourcesController, type: :routing do 4 | describe "routing" do 5 | 6 | it "routes to #index" do 7 | expect(:get => "/api_resources").to route_to("api_resources#index") 8 | end 9 | 10 | it "routes to #new" do 11 | expect(:get => "/api_resources/new").to route_to("api_resources#new") 12 | end 13 | 14 | it "routes to #show" do 15 | expect(:get => "/api_resources/1").to route_to("api_resources#show", :id => "1") 16 | end 17 | 18 | it "routes to #edit" do 19 | expect(:get => "/api_resources/1/edit").to route_to("api_resources#edit", :id => "1") 20 | end 21 | 22 | it "routes to #create" do 23 | expect(:post => "/api_resources").to route_to("api_resources#create") 24 | end 25 | 26 | it "routes to #update via PUT" do 27 | expect(:put => "/api_resources/1").to route_to("api_resources#update", :id => "1") 28 | end 29 | 30 | it "routes to #update via PATCH" do 31 | expect(:patch => "/api_resources/1").to route_to("api_resources#update", :id => "1") 32 | end 33 | 34 | it "routes to #destroy" do 35 | expect(:delete => "/api_resources/1").to route_to("api_resources#destroy", :id => "1") 36 | end 37 | 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. 2 | # Conventionally, all specs live under a `spec` directory, which RSpec adds to 3 | # the `$LOAD_PATH`. 4 | # The generated `.rspec` file contains `--require spec_helper` which will cause 5 | # this file to always be loaded, without a need to explicitly require it in any 6 | # files. 7 | # 8 | # Given that it is always loaded, you are encouraged to keep this file as 9 | # light-weight as possible. Requiring heavyweight dependencies from this file 10 | # will add to the boot time of your test suite on EVERY test run, even for an 11 | # individual file that may not need all of that loaded. Instead, consider making 12 | # a separate helper file that requires the additional dependencies and performs 13 | # the additional setup, and require it from the spec files that actually need 14 | # it. 15 | # 16 | # The `.rspec` file also contains a few flags that are not defaults but that 17 | # users commonly want. 18 | # 19 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 20 | RSpec.configure do |config| 21 | # rspec-expectations config goes here. You can use an alternate 22 | # assertion/expectation library such as wrong or the stdlib/minitest 23 | # assertions if you prefer. 24 | config.expect_with :rspec do |expectations| 25 | # This option will default to `true` in RSpec 4. It makes the `description` 26 | # and `failure_message` of custom matchers include text for helper methods 27 | # defined using `chain`, e.g.: 28 | # be_bigger_than(2).and_smaller_than(4).description 29 | # # => "be bigger than 2 and smaller than 4" 30 | # ...rather than: 31 | # # => "be bigger than 2" 32 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 33 | end 34 | # rspec-mocks config goes here. You can use an alternate test double 35 | # library (such as bogus or mocha) by changing the `mock_with` option here. 36 | config.mock_with :rspec do |mocks| 37 | # Prevents you from mocking or stubbing a method that does not exist on 38 | # a real object. This is generally recommended, and will default to 39 | # `true` in RSpec 4. 40 | mocks.verify_partial_doubles = true 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/support/helpers/x509_certificate_helper.rb: -------------------------------------------------------------------------------- 1 | class CertificateHelper 2 | def initialize 3 | @key = OpenSSL::PKey::RSA.new(1024) 4 | @public_key = @key.public_key 5 | 6 | subject = "/C=BE/O=Test/OU=Test/CN=Test" 7 | 8 | @cert = OpenSSL::X509::Certificate.new 9 | @cert.subject = @cert.issuer = OpenSSL::X509::Name.parse(subject) 10 | @cert.not_before = Time.now 11 | @cert.not_after = Time.now + 1 * 24 * 60 * 60 12 | @cert.public_key = @public_key 13 | @cert.serial = 0x0 14 | @cert.version = 2 15 | 16 | @cert.sign @key, OpenSSL::Digest::SHA256.new 17 | end 18 | 19 | def get_cert 20 | @cert.to_pem 21 | end 22 | 23 | def get_private_key 24 | @key.to_s 25 | end 26 | 27 | def get_fingerprint 28 | OpenSSL::Digest::SHA256.new(@cert.to_der).to_s 29 | end 30 | 31 | end 32 | 33 | -------------------------------------------------------------------------------- /spec/views/api_resources/edit.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "api_resources/edit", type: :view do 4 | before(:each) do 5 | @api_resource = assign(:api_resource, ApiResource.create!( 6 | :name => "MyString", 7 | :description => "MyString", 8 | :access_key => "MyString" 9 | )) 10 | end 11 | 12 | it "renders the edit api_resource form" do 13 | render 14 | 15 | assert_select "form[action=?][method=?]", api_resource_path(@api_resource), "post" do 16 | 17 | assert_select "input#api_resource_name[name=?]", "api_resource[name]" 18 | 19 | assert_select "input#api_resource_description[name=?]", "api_resource[description]" 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/views/api_resources/index.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "api_resources/index", type: :view do 4 | before(:each) do 5 | assign(:api_resources, [ 6 | ApiResource.create!( 7 | :name => "Name", 8 | :description => "Description", 9 | :access_key => "Access Key" 10 | ), 11 | ApiResource.create!( 12 | :name => "Name2", 13 | :description => "Description", 14 | :access_key => "Access Key" 15 | ) 16 | ]) 17 | end 18 | 19 | it "renders a list of api_resources" do 20 | render 21 | assert_select "tr>td", :text => "Name".to_s, :count => 1 22 | assert_select "tr>td", :text => "Description".to_s, :count => 2 23 | assert_select "tr>td", :text => "Regenerate".to_s, :count => 2 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/views/api_resources/new.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "api_resources/new", type: :view do 4 | before(:each) do 5 | assign(:api_resource, ApiResource.new( 6 | :name => "MyString", 7 | :description => "MyString", 8 | :access_key => "MyString" 9 | )) 10 | end 11 | 12 | it "renders new api_resource form" do 13 | render 14 | 15 | assert_select "form[action=?][method=?]", api_resources_path, "post" do 16 | 17 | assert_select "input#api_resource_name[name=?]", "api_resource[name]" 18 | 19 | assert_select "input#api_resource_description[name=?]", "api_resource[description]" 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/views/api_resources/show.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe "api_resources/show", type: :view do 4 | before(:each) do 5 | @api_resource = assign(:api_resource, ApiResource.create!( 6 | :name => "Name", 7 | :description => "Description", 8 | :access_key => "Access Key" 9 | )) 10 | end 11 | 12 | it "renders attributes in

" do 13 | render 14 | expect(rendered).to match(/Name/) 15 | expect(rendered).to match(/Description/) 16 | expect(rendered).to match(/Access Key/) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/views/groups/show.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe 'groups/show', type: :view do 2 | let(:admin) { create(:admin_user) } 3 | let(:group) { create(:group) } 4 | 5 | context 'authorized as admin' do 6 | it 'should renders form to add user to group' do 7 | sign_in admin 8 | assign(:group, group) 9 | assign(:group_users, []) 10 | 11 | render 12 | 13 | assert_select 'form[action=?][method=?]', add_user_to_group_path(group.id), 'post' do 14 | assert_select 'input#add_user_user_id[name=user_id]' 15 | assert_select 'input#expiration_date[name=expiration_date][type=date]' 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/layouts/home.html.slim_spec.rb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | 3 | RSpec.describe 'layouts/home', type: :view do 4 | before(:each) do 5 | @cached_sign_in_type = ENV['SIGN_IN_TYPE'] 6 | end 7 | 8 | after(:each) do 9 | ENV['SIGN_IN_TYPE'] = @cached_sign_in_type 10 | end 11 | 12 | it 'should renders google auth link when use default sign in type' do 13 | ENV['SIGN_IN_TYPE'] = '' 14 | 15 | render 16 | 17 | assert_select "a[href$='#{user_google_oauth2_omniauth_authorize_path}']" 18 | end 19 | 20 | it 'should not renders google auth link when sign in type form' do 21 | ENV['SIGN_IN_TYPE'] = 'form' 22 | 23 | render 24 | 25 | assert_select "a[href$='#{user_google_oauth2_omniauth_authorize_path}']", 0 26 | end 27 | 28 | it 'renders sign in form' do 29 | ENV['SIGN_IN_TYPE'] = 'form' 30 | 31 | render 32 | 33 | assert_select 'form[action=?][method=?]', user_sign_in_path, 'post' do 34 | assert_select 'input#name[name=name]' 35 | assert_select 'input#email[name=email]' 36 | end 37 | end 38 | 39 | it 'should not renders sign in form when sign in type is not form' do 40 | ENV['SIGN_IN_TYPE'] = 'not_form' 41 | 42 | render 43 | 44 | assert_select 'form[action=?][method=?]', user_sign_in_path, 'post', 0 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gate-sso/gate/958d5b920b07a23a7e7d0dbf76e1ad783dc11009/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------