diff --git a/CHANGELOG.md b/CHANGELOG.md index a742e960c..cdee71470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,139 @@ +19.02.2015 + +Go to registry shared folder and setup CA directory tree: +``` +mkdir ca +cd ca +mkdir certs crl newcerts private csrs +chmod 700 private +touch index.txt +echo 1000 > serial +``` + +Generate the root key (prompts for pass phrase): +``` +openssl genrsa -aes256 -out private/ca.key.pem 4096 +``` + +Configure OpenSSL: +``` +sudo su - +cd /etc/ssl/ +cp openssl.cnf openssl.cnf.bak +nano openssl.cnf +exit +``` + +Make sure the following options are in place: +``` +[ CA_default ] +# Where everything is kept +dir = /home/registry/registry/shared/ca + +[ usr_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +nsComment = "OpenSSL Generated Certificate" +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +[ v3_ca ] +# Extensions for a typical CA +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer +basicConstraints = CA:true +keyUsage = cRLSign, keyCertSign + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional +``` + +Issue the root certificate (prompts for additional data): +``` +openssl req -new -x509 -days 3650 -key private/ca.key.pem -sha256 -extensions v3_ca -out certs/ca.crt.pem +chmod 444 certs/ca.crt.pem +``` + +Create a CSR for the webclient: +``` +openssl genrsa -out private/webclient.key.pem 4096 +chmod 400 private/webclient.key.pem +openssl req -sha256 -new -key private/webclient.key.pem -out csrs/webclient.csr.pem +``` + +Sign the request and create certificate: +``` +openssl ca -keyfile private/ca.key.pem -cert certs/ca.crt.pem -extensions usr_cert -notext -md sha256 -in csrs/webclient.csr.pem -out certs/webclient.crt.pem +``` + +Configure EPP virtual host: +``` +sudo nano /etc/apache2/sites-enabled/epp.conf +``` + +Replace this line: +``` +SSLVerifyClient optional_no_ca +``` + +With these lines: +``` + SSLVerifyClient require + SSLVerifyDepth 1 + SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.crt.pem + RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s" +``` + +Configure webclient virtual host: +``` +sudo nano /etc/apache2/sites-enabled/webclient.conf +``` + +Add these lines: +``` + SSLVerifyClient none + SSLVerifyDepth 1 + SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.crt.pem + + RequestHeader set SSL_CLIENT_S_DN_CN "" + + + SSLVerifyClient require + + + + SSLVerifyClient require + RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s" + +``` + +Reload apache: +``` +sudo a2enmod headers +sudo /etc/init.d/apache2 restart +``` + +Configure registry and epp application.yml to match the CA settings: +``` +ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' +ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' +ca_key_password: 'registryalpha' +webclient_ip: '54.154.91.240' +``` + +Configure webclient application.yml to match the CA settings: +``` +cert_path: '/home/registry/registry/shared/ca/certs/webclient.crt.pem' +key_path: '/home/registry/registry/shared/ca/private/webclient.key.pem' +``` + 20.01.2015 * Added dedicated mina cron:setup and mina cron:clear for manual cron management. diff --git a/README.md b/README.md index 92b8f67c6..2733fd2bd 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,8 @@ Be sure to update paths to match your system configuration. SSLVerifyClient require SSLVerifyDepth 1 - SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.cert.pem + SSLCACertificateFile /home/registry/registry/shared/ca/certs/ca.crt.pem + RequestHeader set SSL_CLIENT_S_DN_CN "%{SSL_CLIENT_S_DN_CN}s" EPPEngine On EPPCommandRoot /proxy/command @@ -181,6 +182,86 @@ All registry demo data can be found at: Initially you can use two type of users: admin users and EPP users. +### CA + +Go to registry shared folder and setup CA directory tree: +``` +mkdir ca +cd ca +mkdir certs crl newcerts private csrs +chmod 700 private +touch index.txt +echo 1000 > serial +``` + +Generate the root key (prompts for pass phrase): +``` +openssl genrsa -aes256 -out private/ca.key.pem 4096 +``` + +Configure OpenSSL: +``` +sudo su - +cd /etc/ssl/ +cp openssl.cnf openssl.cnf.bak +nano openssl.cnf +exit +``` + +Make sure the following options are in place: +``` +[ CA_default ] +# Where everything is kept +dir = /home/registry/registry/shared/ca + +[ usr_cert ] +# These extensions are added when 'ca' signs a request. +basicConstraints=CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +nsComment = "OpenSSL Generated Certificate" +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +[ v3_ca ] +# Extensions for a typical CA +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer +basicConstraints = CA:true +keyUsage = cRLSign, keyCertSign + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional +``` + +Issue the root certificate (prompts for additional data): +``` +openssl req -new -x509 -days 3650 -key private/ca.key.pem -sha256 -extensions v3_ca -out certs/ca.crt.pem +chmod 444 certs/ca.crt.pem +``` + +Create a CSR for the webclient: +``` +openssl genrsa -out private/webclient.key.pem 4096 +chmod 400 private/webclient.key.pem +openssl req -sha256 -new -key private/webclient.key.pem -out csrs/webclient.csr.pem +``` + +Sign the request and create certificate: +``` +openssl ca -keyfile private/ca.key.pem -cert certs/ca.crt.pem -extensions usr_cert -notext -md sha256 -in csrs/webclient.csr.pem -out certs/webclient.crt.pem +``` + +Certificates for API Users are generated via the user interface. CSR must be uploaded for each API User. Certificates are created automatically after saving the user. + +Private key and certificate must be packaged to pkcs12 and added to the browser's certificate bank. + +Make sure application configuration files contain correct paths to certificates. ### EPP web client diff --git a/app/api/repp/api.rb b/app/api/repp/api.rb index 04b805597..ec0b3167f 100644 --- a/app/api/repp/api.rb +++ b/app/api/repp/api.rb @@ -3,8 +3,18 @@ module Repp format :json prefix :repp - http_basic do |username, password| - @current_user ||= ApiUser.find_by(username: username, password: password) + before do + auth_param = request.headers['Authorization'].split(' ', 2).second + username, password = ::Base64.decode64(auth_param || '').split(':', 2) + + # allow user lookup only by username if request came from webclient + if request.ip == APP_CONFIG['webclient_ip'] && password.blank? + login_params = { username: username } + else + login_params = { username: username, password: password } + end + + @current_user ||= ApiUser.find_by(login_params) end helpers do diff --git a/app/controllers/epp/sessions_controller.rb b/app/controllers/epp/sessions_controller.rb index 21161c7a0..6a4696e49 100644 --- a/app/controllers/epp/sessions_controller.rb +++ b/app/controllers/epp/sessions_controller.rb @@ -5,10 +5,23 @@ class Epp::SessionsController < EppController render_epp_response('greeting') end + # rubocop: disable Metrics/PerceivedComplexity + # rubocop: disable Metrics/CyclomaticComplexity def login - @api_user = ApiUser.find_by(login_params) + cert_valid = true + # Allow login with only username + if request.ip == APP_CONFIG['webclient_ip'] && login_params[:password].nil? + @api_user = ApiUser.find_by(username: login_params[:username]) + elsif request.ip == APP_CONFIG['webclient_ip'] + @api_user = ApiUser.find_by(login_params) + else + if request.env['HTTP_SSL_CLIENT_S_DN_CN'] != login_params[:username] + cert_valid = false + end + @api_user = ApiUser.find_by(login_params) + end - if @api_user.try(:active) + if @api_user.try(:active) && cert_valid epp_session[:api_user_id] = @api_user.id render_epp_response('login_success') else @@ -16,6 +29,8 @@ class Epp::SessionsController < EppController render_epp_response('login_fail') end end + # rubocop: enable Metrics/PerceivedComplexity + # rubocop: enable Metrics/CyclomaticComplexity def logout @api_user = current_user # cache current_user for logging diff --git a/app/models/api_user.rb b/app/models/api_user.rb index aee1ff203..1dd0b6ea6 100644 --- a/app/models/api_user.rb +++ b/app/models/api_user.rb @@ -9,7 +9,7 @@ class ApiUser < User validates :username, :password, :registrar, presence: true validates :username, uniqueness: true - # before_save :create_crt, if: -> (au) { au.csr_changed? } + before_save :create_crt, if: -> (au) { au.csr_changed? } attr_accessor :registrar_typeahead diff --git a/app/views/admin/api_users/show.haml b/app/views/admin/api_users/show.haml index f8f09a701..63ffc3952 100644 --- a/app/views/admin/api_users/show.haml +++ b/app/views/admin/api_users/show.haml @@ -43,7 +43,7 @@ %dd - %dt= t('crt') - / - if @api_user.csr - / %dd= link_to(t('download'), download_crt_admin_api_user_path) - / - else - / %dd - + - if @api_user.csr + %dd= link_to(t('download'), download_crt_admin_api_user_path) + - else + %dd - diff --git a/config/routes.rb b/config/routes.rb index cd9f85b81..e2bb835b3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,7 @@ require 'epp_constraint' Rails.application.routes.draw do namespace(:epp, defaults: { format: :xml }) do match 'session/:action', controller: 'sessions', via: :all + match 'session/pki/:action', controller: 'sessions', via: :all post 'command/:action', controller: 'domains', constraints: EppConstraint.new(:domain) post 'command/:action', controller: 'contacts', constraints: EppConstraint.new(:contact)