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)