diff --git a/lib/NGCP/Panel/Controller/API/Contacts.pm b/lib/NGCP/Panel/Controller/API/Contacts.pm index e90d6ab56c..788cf95872 100644 --- a/lib/NGCP/Panel/Controller/API/Contacts.pm +++ b/lib/NGCP/Panel/Controller/API/Contacts.pm @@ -17,10 +17,12 @@ use HTTP::Status qw( HTTP_OK HTTP_UNPROCESSABLE_ENTITY HTTP_UNSUPPORTED_MEDIA_TYPE + HTTP_INTERNAL_SERVER_ERROR ); -use JE qw(); -use JSON qw(); +#use JE qw(); +use JSON qw(from_json); use MooseX::ClassAttribute qw(class_has); +use NGCP::Panel::Form::Contact::Admin qw(); use NGCP::Panel::Form::Contact::Reseller qw(); use NGCP::Panel::ValidateJSON qw(); use Path::Tiny qw(path); @@ -123,55 +125,43 @@ sub OPTIONS : Allow { sub POST : Allow { my ($self, $c) = @_; - my $media_type = 'application/hal+json'; + my $media_type = 'application/json'; { last unless $self->forbid_link_header($c); last unless $self->valid_media_type($c, $media_type); last unless $self->require_body($c); my $json = do { local $/; $c->request->body->getline }; # slurp last unless $self->require_wellformed_json($c, $media_type, $json); - last unless $self->valid_entity($c, $json); - my $hal = Data::HAL->from_json($json); + #last unless $self->valid_entity($c, $json); - my $r_id; - { - my $reseller_link = ($hal->links // [])->grep(sub { - $_->relation->eq('http://purl.org/sipwise/ngcp-api/#rel-resellers') - }); - - if ($reseller_link->size) { - my $reseller_uri = URI->new_abs($reseller_link->at(0)->href->as_string, $c->req->uri)->canonical; - my $resellers_uri = URI->new_abs('/api/resellers/', $c->req->uri)->canonical; - if (0 != index $reseller_uri, $resellers_uri) { - $c->response->status(HTTP_UNPROCESSABLE_ENTITY); - $c->response->header('Content-Language' => 'en'); - $c->response->content_type('application/xhtml+xml'); - $c->stash( - template => 'api/unprocessable_entity.tt', - error_message => "The link $reseller_uri cannot express a reseller relationship.", - ); - last; - } - $r_id = $reseller_uri->rel($resellers_uri)->query_param('id'); - last unless $self->valid_id($c, $r_id); - } + my $contact_form; + my $resource = from_json($json); + $resource->{reseller}{id} = delete $resource->{reseller_id}; + if($c->user->roles eq "api_admin") { + $c->log->debug("+++++++++++++++ using NGCP::Panel::Form::Contact::Admin for validation"); + $contact_form = NGCP::Panel::Form::Contact::Admin->new; + } else { + $contact_form = NGCP::Panel::Form::Contact::Reseller->new; + $resource->{reseller}{id} = $c->user->reseller_id; } - my $resource = $hal->resource; - - my $contact_form = NGCP::Panel::Form::Contact::Reseller->new; - my %fields = map { $_->name => undef } grep { 'Text' eq $_->type || 'Email' eq $_->type } $contact_form->fields; + my %fields = map { $_->name => undef } $contact_form->fields; for my $k (keys %{ $resource }) { - delete $resource->{$k} unless exists $fields{$k}; + unless(exists $fields{$k}) { + $c->log->debug("+++++++++++++ deleting unknown key '$k'"); + delete $resource->{$k}; + } $resource->{$k} = DateTime::Format::RFC3339->format_datetime($resource->{$k}) if $resource->{$k}->$_isa('DateTime'); } + my $result = $contact_form->run(params => $resource); if ($result->error_results->size) { $c->response->status(HTTP_UNPROCESSABLE_ENTITY); $c->response->header('Content-Language' => 'en'); + # TODO: return error in json! $c->response->content_type('application/xhtml+xml'); my $e = $result->error_results->map(sub { - sprintf '%s: %s - %s', $_->name, $_->input, $_->errors->join(q()) + sprintf 'field: \'%s\', input: \'%s\', errors: %s', $_->name, $_->input // '', $_->errors->join(q()) })->join("\n"); $c->stash( template => 'api/unprocessable_entity.tt', @@ -180,11 +170,23 @@ sub POST : Allow { last; } - $resource->{reseller_id} = $r_id; + $resource->{reseller_id} = $resource->{reseller}{id}; delete $resource->{reseller}; my $now = DateTime->now; $resource->{create_timestamp} = $now; $resource->{modify_timestamp} = $now; - my $contact = $c->model('DB')->resultset('contacts')->create($resource); + my $contact; + try { + $contact = $c->model('DB')->resultset('contacts')->create($resource); + } catch($e) { + $c->log->error("failed to create contact: $e"); # TODO: log user, input etc + $c->response->status(HTTP_INTERNAL_SERVER_ERROR); + # TODO: that one is not rendered, rather than our "normal" 500 template! + $c->stash( + template => 'api/internal_server_error.tt', + error_message => "DB query faild: $e", + ); + last; + } $c->cache->remove($c->request->uri->canonical->as_string); $c->response->status(HTTP_CREATED); @@ -258,6 +260,7 @@ sub hal_from_contact : Private { my %resource = $contact->get_inflated_columns; my $id = delete $resource{id}; + my $hal = Data::HAL->new( links => [ Data::HAL::Link->new( @@ -331,7 +334,7 @@ sub valid_media_type : Private { $c->stash(template => 'api/valid_media_type.tt', media_type => $media_type); return; } - +=pod sub valid_entity : Private { my ($self, $c, $entity) = @_; my $js @@ -358,6 +361,7 @@ sub valid_entity : Private { } return 1; } +=cut sub end : Private { my ($self, $c) = @_; @@ -390,3 +394,5 @@ use Carp qw(longmess); use DateTime::Format::RFC3339 qw(); use Data::Dumper qw(D $c->detach($c->view); } } + +# vim: set tabstop=4 expandtab: diff --git a/sandbox/api_auth.pl b/sandbox/api_auth.pl index 141f019a6b..61820acd0a 100755 --- a/sandbox/api_auth.pl +++ b/sandbox/api_auth.pl @@ -7,6 +7,7 @@ $ua->ssl_opts( SSL_cert_file => '/etc/ssl/ngcp/api/NGCP-API-client-certificate-1385650532.pem', SSL_key_file => '/etc/ssl/ngcp/api/NGCP-API-client-certificate-1385650532.pem', SSL_ca_file => '/etc/ssl/ngcp/api/ca-cert.pem', +); my $can_accept = HTTP::Message::decodable; my $res = $ua->get( 'https://serenity:4443/api/contacts/?id=10', diff --git a/share/static/js/api/properties/contacts-item.json b/share/static/js/api/properties/contacts-item.json index 709e96650a..d37303f5f5 100644 --- a/share/static/js/api/properties/contacts-item.json +++ b/share/static/js/api/properties/contacts-item.json @@ -3,6 +3,7 @@ "description": "contact information for a contract", "required": ["city", "company", "country", "email", "firstname", "lastname", "phonenumber", "postcode", "street"], "properties": { + "reseller_id": { "type": ["null", "number"], "description": "The id of the contact's reseller." }, "city": { "type": ["null", "string"], "description": "The contact's city." }, "company": { "type": ["null", "string"], "description": "The contact's company." }, "country": { "type": ["null", "string"], "description": "The contact's country (ISO-3166, e.g. \"AT\" for Austria, \"DE\" for Germany)." }, diff --git a/share/templates/api/internal_sever_error.tt b/share/templates/api/internal_sever_error.tt new file mode 100644 index 0000000000..d6169988a2 --- /dev/null +++ b/share/templates/api/internal_sever_error.tt @@ -0,0 +1,10 @@ + + +
+An error occured during processing the request.
+[% error_message | html %]
+ + diff --git a/t/api-auth.t b/t/api-auth.t new file mode 100644 index 0000000000..169adeb227 --- /dev/null +++ b/t/api-auth.t @@ -0,0 +1,61 @@ +use Sipwise::Base; +use Net::Domain qw(hostfqdn); +use LWP::UserAgent; +use Test::More; + +my $uri = $ENV{CATALYST_SERVER} || ('https://'.hostfqdn.':4443'); + +my $valid_ssl_client_cert = $ENV{API_SSL_CLIENT_CERT} || + "/etc/ssl/ngcp/api/NGCP-API-client-certificate.pem"; +my $valid_ssl_client_key = $ENV{API_SSL_CLIENT_KEY} || + $valid_ssl_client_cert; + +my $invalid_ssl_client_cert = $ENV{API_SSL_INVALID_CLIENT_CERT} || + "/etc/ssl/ngcp/api/NGCP-API-client-certificate.invalid.pem"; +my $invalid_ssl_client_key = $ENV{API_SSL_INVALID_CLIENT_KEY} || + $invalid_ssl_client_cert; + +my $unauth_ssl_client_cert = $ENV{API_SSL_UNAUTH_CLIENT_CERT} || + "/etc/ssl/ngcp/api/NGCP-API-client-certificate.unauth.pem"; +my $unauth_ssl_client_key = $ENV{API_SSL_UNAUTH_CLIENT_KEY} || + $unauth_ssl_client_cert; + +my $ssl_ca_cert = $ENV{API_SSL_CA_CERT} || "/etc/ssl/ngcp/api/ca-cert.pem"; + +my ($ua, $res); +$ua = LWP::UserAgent->new; + +# invalid cert +$ua->ssl_opts( + SSL_cert_file => $invalid_ssl_client_cert, + SSL_key_file => $invalid_ssl_client_key, + SSL_ca_file => $ssl_ca_cert, +); +$res = $ua->get($uri.'/api/'); +ok($res->code == 400, "check invalid client certificate"); + +# unauth cert +$ua->ssl_opts( + SSL_cert_file => $unauth_ssl_client_cert, + SSL_key_file => $unauth_ssl_client_key, + SSL_ca_file => $ssl_ca_cert, +); +$res = $ua->get($uri.'/api/'); +ok($res->code == 403, "check unauthorized client certificate"); + +# successful auth +$ua->ssl_opts( + SSL_cert_file => $valid_ssl_client_cert, + SSL_key_file => $valid_ssl_client_key, + SSL_ca_file => $ssl_ca_cert, +); +$res = $ua->get($uri.'/api/'); +ok($res->code == 200, "check valid client certificate"); + +#my @links = $res->header('Link'); +#ok(grep /^<\/api\/contacts\/>; rel="collection /, @links); +#ok(grep /^<\/api\/contracts\/>; rel="collection /, @links); + +done_testing; + +# vim: set tabstop=4 expandtab: