Merge branch 'master' of github.com:internetee/registry

This commit is contained in:
Martin Lensment 2014-12-22 13:54:27 +02:00
commit 66b6778243
20 changed files with 290 additions and 34 deletions

View file

@ -307,3 +307,9 @@ Rollback to previous release:
mina rollback # staging
mina pr rollback # production
General rake and mina tips:
rake -T # list all rake commands
rake -T db # list all database related commands
mina -T # list all mina deploy commands

View file

@ -10,7 +10,8 @@ module Epp::ContactsHelper
# FIXME: Update returns 2303 update multiple times
code = params_hash['epp']['command']['update']['update'][:id]
@contact = Contact.where(code: code).first
if update_rights? && stamp(@contact) && @contact.update_attributes(contact_and_address_attributes(:update))
# if update_rights? && stamp(@contact) && @contact.update_attributes(contact_and_address_attributes(:update))
if owner? && stamp(@contact) && @contact.update_attributes(contact_and_address_attributes(:update))
render 'epp/contacts/update'
else
contact_exists?(code)
@ -38,8 +39,8 @@ module Epp::ContactsHelper
def info_contact
handle_errors(@contact) and return unless @contact
handle_errors(@contact) and return unless rights?
@disclosure = ContactDisclosure.default_values.merge(@contact.disclosure.as_hash)
@disclosure_policy = @contact.disclosure.attributes_with_flag
@disclosure = ContactDisclosure.default_values.merge(@contact.disclosure.try(:as_hash) || {})
@disclosure_policy = @contact.disclosure.try(:attributes_with_flag)
@owner = owner?(false)
render 'epp/contacts/info'
end
@ -67,7 +68,8 @@ module Epp::ContactsHelper
def validate_contact_update_request
@ph = params_hash['epp']['command']['update']['update']
update_attrs_present?
xml_attrs_present?(@ph, [['id'], %w(authInfo pw)])
# xml_attrs_present?(@ph, [['id'], %w(authInfo pw)])
xml_attrs_present?(@ph, [['id']])
end
def contact_exists?(code)

View file

@ -11,13 +11,18 @@ module DomainVersionObserver
name = domain_name
return unless name
body = snapshot
delay.update_whois(name, body)
delay.update_private_whois(name, body)
delay.update_public_whois(name, body)
end
# not sure we need to pass in the params since i don't know if delayed job has access to
# all the regular attributes and stuff
def update_whois(domain_name, body)
wd = WhoisDomain.find_or_initialize_by(name: domain_name)
def update_private_whois(domain_name, body)
wd = Whois::PublicDomain.find_or_initialize_by(name: domain_name)
wd.body = body
wd.save!
end
def update_public_whois(domain_name, body)
wd = Whois::PrivateDomain.find_or_initialize_by(name: domain_name)
wd.body = body
wd.save!
end

View file

@ -9,6 +9,7 @@ class Contact < ActiveRecord::Base
has_many :domain_contacts
has_many :domains, through: :domain_contacts
has_many :statuses, class_name: 'ContactStatus'
# TODO: remove the x_by
belongs_to :created_by, class_name: 'EppUser', foreign_key: :created_by_id

View file

@ -0,0 +1,78 @@
class ContactStatus < ActiveRecord::Base
include EppErrors
belongs_to :contact
CLIENT_DELETE_PROHIBITED = 'clientDeleteProhibited'
SERVER_DELETE_PROHIBITED = 'serverDeleteProhibited'
CLIENT_HOLD = 'clientHold'
SERVER_HOLD = 'serverHold'
CLIENT_RENEW_PROHIBITED = 'clientRenewProhibited'
SERVER_RENEW_PROHIBITED = 'serverRenewProhibited'
CLIENT_TRANSFER_PROHIBITED = 'clientTransferProhibited'
SERVER_TRANSFER_PROHIBITED = 'serverTransferProhibited'
CLIENT_UPDATE_PROHIBITED = 'clientUpdateProhibited'
SERVER_UPDATE_PROHIBITED = 'serverUpdateProhibited'
INACTIVE = 'inactive'
OK = 'ok'
PENDING_CREATE = 'pendingCreate'
PENDING_DELETE = 'pendingDelete'
PENDING_RENEW = 'pendingRenew'
PENDING_TRANSFER = 'pendingTransfer'
PENDING_UPDATE = 'pendingUpdate'
SERVER_MANUAL_INZONE = 'serverManualInzone'
SERVER_REGISTRANT_CHANGE_PROHIBITED = 'serverRegistrantChangeProhibited'
SERVER_ADMIN_CHANGE_PROHIBITED = 'serverAdminChangeProhibited'
SERVER_TECH_CHANGE_PROHIBITED = 'serverTechChangeProhibited'
FORCE_DELETE = 'forceDelete'
DELETE_CANDIDATE = 'deleteCandidate'
EXPIRED = 'expired'
STATUSES = [
CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED, CLIENT_HOLD, SERVER_HOLD,
CLIENT_RENEW_PROHIBITED, SERVER_RENEW_PROHIBITED, CLIENT_TRANSFER_PROHIBITED,
SERVER_TRANSFER_PROHIBITED, CLIENT_UPDATE_PROHIBITED, SERVER_UPDATE_PROHIBITED,
INACTIVE, OK, PENDING_CREATE, PENDING_DELETE, PENDING_RENEW, PENDING_TRANSFER,
PENDING_UPDATE, SERVER_MANUAL_INZONE, SERVER_REGISTRANT_CHANGE_PROHIBITED,
SERVER_ADMIN_CHANGE_PROHIBITED, SERVER_TECH_CHANGE_PROHIBITED, FORCE_DELETE,
DELETE_CANDIDATE, EXPIRED
]
CLIENT_STATUSES = [
CLIENT_DELETE_PROHIBITED, CLIENT_HOLD, CLIENT_RENEW_PROHIBITED, CLIENT_TRANSFER_PROHIBITED,
CLIENT_UPDATE_PROHIBITED
]
SERVER_STATUSES = [
SERVER_DELETE_PROHIBITED, SERVER_HOLD, SERVER_RENEW_PROHIBITED, SERVER_TRANSFER_PROHIBITED,
SERVER_UPDATE_PROHIBITED, SERVER_MANUAL_INZONE, SERVER_REGISTRANT_CHANGE_PROHIBITED,
SERVER_ADMIN_CHANGE_PROHIBITED, SERVER_TECH_CHANGE_PROHIBITED
]
def epp_code_map
{
'2302' => [ # Object exists
[:value, :taken, { value: { obj: 'status', val: value } }]
]
}
end
def server_status?
SERVER_STATUSES.include?(value)
end
def client_status?
CLIENT_STATUSES.include?(value)
end
class << self
def statuses_for_client
CLIENT_STATUSES.map { |x| x.sub('client', '') }
end
def statuses_for_admin
SERVER_STATUSES.map { |x| x.sub('server', '') }
end
end
end

2
app/models/whois.rb Normal file
View file

@ -0,0 +1,2 @@
module Whois
end

View file

@ -0,0 +1,5 @@
module Whois
class PrivateDomain < PrivateServer
self.table_name = 'domains'
end
end

View file

@ -0,0 +1,6 @@
module Whois
class PrivateServer < ActiveRecord::Base
self.abstract_class = true
establish_connection :"#{Rails.env}_private_whois"
end
end

View file

@ -0,0 +1,5 @@
module Whois
class PublicDomain < PublicServer
self.table_name = 'domains'
end
end

View file

@ -0,0 +1,6 @@
module Whois
class PublicServer < ActiveRecord::Base
self.abstract_class = true
establish_connection :"#{Rails.env}_public_whois"
end
end

View file

@ -1,3 +0,0 @@
class WhoisDomain < WhoisServer
self.table_name = 'domains'
end

View file

@ -1,4 +0,0 @@
class WhoisServer < ActiveRecord::Base
self.abstract_class = true
establish_connection :"#{Rails.env}_whois"
end

View file

@ -16,12 +16,17 @@ xml.epp_head do
xml.tag!('contact:crDate', @contact.created_at)
xml.tag!('contact:upID', @contact.up_id) if @contact.up_id
xml.tag!('contact:upDate', @contact.updated_at) unless @contact.updated_at == @contact.created_at
xml.tag!('contact:ident', @contact.ident, type: @contact.ident_type)
xml.tag!('contact:trDate', '123') if false
if @owner
xml.tag!('contact:authInfo') do
xml.tag!('contact:pw', @contact.auth_info) # Doc says we have to return this but is it necessary?
end
end
# statuses
@contact.statuses.each do |cs|
xml.tag!('contact:status', s: cs.value)
end
xml << render('/epp/contacts/disclosure_policy')
end
end

View file

@ -18,8 +18,18 @@ production:
<<: *default
database: registry_production
development_whois:
database: whois_development
development_private_whois:
<<: *default
database: whois_private
test_whois:
database: test_whois
development_private_whois:
<<: *default
database: whois_public
production_public_whois:
<<: *default
database: production_whois_public
production_private_whois:
<<: *default
database: production_whois_private

View file

@ -0,0 +1,10 @@
class CreateContactStatuses < ActiveRecord::Migration
def change
create_table :contact_statuses do |t|
t.string :value
t.string :description
t.belongs_to :contact
t.timestamps
end
end
end

View file

@ -59,6 +59,14 @@ ActiveRecord::Schema.define(version: 20141218154829) do
t.boolean "address"
end
create_table "contact_statuses", force: true do |t|
t.string "value"
t.string "description"
t.integer "contact_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "contact_versions", force: true do |t|
t.string "item_type", null: false
t.integer "item_id", null: false

61
doc/ssl.md Normal file
View file

@ -0,0 +1,61 @@
Setting up client-side certificate authentication
-------------------------------------------------
This is written and tested on apache2.
Requires openSSL, tested on OpenSSL version 1.0.1f 6 Jan 2014.
First, setup openssl for use in being a certificate authority. For that you have to edit openssl.conf ( on debian based systems should be located at /etc/ssl/ )
There are a lot of options there but some basics for example. Your policy_match will probably look different in production, also the default days (of key validity) should probably be not 10 years for production.
```
default_ca = CA_development
[ CA_development ]
dir = /etc/ssl/private
database = $dir/index.txt
serial = $dir/serial
private_key = $dir/ca.key.pem
certificate = $dir/ca.crt
default_days = 3650
default_md = md5
new_certs_dir = $dir
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = match
commonName = supplied
emailAddress = optional
```
Following commands should be run in /etc/ssl/ unless you choose another location for your keys.
Now you need cert authority key which can be generated by
` openssl genrsa -out private/ca.key `
Now generate a new certificate request with `openssl req -new -key private/ca.key -out private/ca.csr`
And sign it `openssl x509 -req -days 3650 -in private/ca.csr -signkey private/ca.key -out private/ca.crt`
Setup the first serial number for our keys, should be a 4 digit hex string `echo FAD0 > private/serial`
Create key database `touch private/index.txt`
And finally, create a cert revocation list for removing user certs `openssl ca -gencrl -out /etc/ssl/private/ca.crl -crldays 7`
Now, we need a certificate for our webserver. Don't bother putting a password on it since you need it to start apache. If there's a good workaround for this, please let us know.
Let's generate the apache key, `openssl genrsa -out private/apache.key`
Create a certificate request for it ` openssl req -new -key apache.key -out apache.csr` and sign it `openssl ca -in private/apache.csr -cert private/ca.crt -keyfile private/ca.key -out private/apache.crt`
Now we are ready to setup apache to use our keys for authentication. A sample apache2 conf
```
SSLEngine on
SSlOptions +StrictRequire
SSLCertificateFile /etc/ssl/private/apache.crt
SSLCertificateKeyFile /etc/ssl/private/apache.key
SSLCACertificateFile /etc/ssl/private/ca.crt
SSLVerifyClient require
```
*replace the repeating lines from previous apache conf with lines from this one*
There could be some more mojo needed to check if Certificates are expired and etc but I haven't really tested it out yet.
Now let's create an example user certificate.
Start off with the key `openssl genrsa -des3 -out $base/users/$1/$1.key 1024` . Now a certificate signing request for that key `openssl req -new -key $base/users/$1/$1.key -out $base/users/$1/$1.csr` and finally let's sign it `openssl ca -in $base/users/$1/$1.csr -cert $base/ca.crt -keyfile $base/ca.key -out $base/users/$1/$1.crt` and we should be done.
In real life (!development), user should generate their own key and cert request.

View file

@ -6,18 +6,20 @@ that disables whois (effects should fully be loaded after restarting the app)
What whois_enabled=false does is that the whois callback does not get included.
Delayed jobs migration and everything else will still be installed tho.
If you wish to use the whois module, tho, you need a whois database looking something like this
Basic whois logic - we save whois data to 2 separate databases - whois private and public.
Those two databases are streamed to appropriate whois servers.
```ruby
create_table :domains do |t|
t.string :name
t.text :body
t.timestamps
end
```
This is still WIP and few whois details need to be sorted out.
NB! Migration with rake tasks is available in whois app repo.
Setting the databases up
__________________________________
Make sure username and password in DATABASES at lib/tasks/whois.rb are correct ( match the ones
in config/database.yml whois_public and whois_private attributes ). We don't load them from
config/database.yml at the moment. So you might have to change them manually.
Finally set the whois app to connect to your whois_public/whois_private database and you're good to go.
Then run `rake whois:create` to create and migrate the databases.
For development, delayed_job queue can be handled by rake task
`rake jobs:work` or if you wish to be fancy you can use a daemon with `bin/delayed_job start`
``

53
lib/tasks/whois.rake Normal file
View file

@ -0,0 +1,53 @@
DATABASES = [
{ database: 'whois_public', host: 'localhost', adapter: 'postgresql', encoding: 'unicode',
pool: '5', username: 'whois', password: 'test', port: '5432' },
{ database: 'whois_private', host: 'localhost', adapter: 'postgresql', encoding: 'unicode',
pool: '5', username: 'whois', password: 'test', port: '5432' }
]
namespace :whois do
task :load_config do
require 'active_record'
require 'pg'
end
desc 'Create whois databases'
task create: [:load_config] do
DATABASES.each do |conf|
create_database(conf)
migrate
end
end
task 'Migrate whois databases'
task migrate: [:load_config] do
DATABASES.each do |conf|
ActiveRecord::Base.establish_connection(conf)
migrate
end
end
def create_database(conf)
ActiveRecord::Base.establish_connection(conf.merge(database: 'postgres'))
ActiveRecord::Base.connection.create_database(conf[:database])
ActiveRecord::Base.establish_connection(conf)
end
def migrate
CreateWhoisBase.up
end
end
class CreateWhoisBase < ActiveRecord::Migration
def self.up
create_table :domains do |t|
t.string :name
t.text :body
t.timestamps
end
end
def self.down
drob_table :domains
end
end

View file

@ -153,9 +153,7 @@ describe 'EPP Contact', epp: true do
expect(response[:results][0][:msg]).to eq('Required parameter missing: add, rem or chg')
expect(response[:results][1][:result_code]).to eq('2003')
expect(response[:results][1][:msg]).to eq('Required parameter missing: id')
expect(response[:results][2][:result_code]).to eq('2003')
expect(response[:results][2][:msg]).to eq('Required parameter missing: pw')
expect(response[:results].count).to eq 3
expect(response[:results].count).to eq 2
end
it 'fails with wrong authentication info' do
@ -163,8 +161,8 @@ describe 'EPP Contact', epp: true do
response = epp_request(update_contact_xml({ id: { value: 'sh8013' } }), :xml, :elkdata)
expect(response[:msg]).to eq('Authentication error')
expect(response[:result_code]).to eq('2200')
expect(response[:msg]).to eq('Authorization error')
expect(response[:result_code]).to eq('2201')
end
it 'is succesful' do