Debugging
curl
In order to isolate where an integration problem is located, it can be helpful to eliminate any custom runtimes and environment specific aspects, and use a standard tool, configured with applicable keys and certificates, and try to communicate with the API. The following guide will use curl , together with the openssl
tool, which are already readily available on many systems.
Prepare your enterprise certificate
To instruct curl to use a client certificate (both the private and public key), it must be available non-encrypted in the PEM format. You likely have your enterprise certificate as an entry in a keystore file, typically a .p12-file (PKCS#12). If you have your enterprise certificate in another format than .p12, you need to figure out how you can extract your certificate to a PEM-file.
We will use openssl to extract the key entry to PEM format. You need to have the following at hand:
the keystore file with your enterprise certificate as a filepath, keystore.p12 is assumed below
password to read the keystore file (and possibly the particular key entry)
Run the following two commands to extract the public certificate and private key from your enterprise certificate into separate PEM files. You will be prompted for the password:
# Extract public certificate chain
openssl pkcs12 --noenc --in keystore.p12 --out publicCertificate.pem --nokeys
# Extract the private key, ensure this file is kept private at all times
openssl pkcs12 --noenc --in keystore.p12 --out privateKey.pem --nocerts
Issue a request to the API
With your enterprise certificate available in the files publicCertificate.pem and privateKey.pem, you should now be able to establish API communication with the Posten signering API.
Substitute ${orgNumber} with the organization number your certificate is issued to. You can also use an organization number you are authorized to send on behalf of.
curl https://api.difitest.signering.posten.no/api/${orgNumber} \
--cert publicCertificate.pem \
--key privateKey.pem \
--insecure
curl https://api.signering.posten.no/api/${orgNumber} \
--cert publicCertificate.pem \
--key privateKey.pem \
--insecure
If you need to view more details about the TLS handshake process, supply the --verbose flag.
Note
Why the --insecure flag? This flag turns off standard TLS validation of the certificate used by the server, specifically disabling the host name validation. The reason for this is our API uses an enterprise certificate as its server certificate, and it is not issued to any specific domain name. curl will not accept the API’s certificate unless this flag is set. An actual integration should do proper validation of the server certificate when establishing the TLS connection.
Responses
If a TLS connection is established (you use an appropriate enterprise certificate), the server will respond accordingly depending on whether your request operates as one of:
You are [the organization number your certificate is issued to]
This means the organization number is authorized to access the API. The request URL contains the same organization number as the certificate is issued to, and you have access to the API.
You are [the organization number your certificate is issued to],
operating on behalf of [organization indicated in the request URL]
This means the organization number your certificate is issued to is authorized to access the API on behalf of the other organization number. The request URL contains another organization number than your certificate is issued to, and authorization is appropriately set up in Posten signering to allow you to integrate on behalf of the organization.
Error responses
Your certificate may be accepted, and TLS connection is established, but may still be denied access because the organization number of your certificate may be missing relevant authorization to access the API.
Your enterprise certificate has been successfully validated as authentic, but the organization number the certificate is issued to has not been granted access to the API.
<error>
<error-code>NOT_AUTHORIZED</error-code>
<error-message>
API authorization request for [organization number], authenticated using certificate
OID.2.5.4.97=NTRNO-[organization number], CN=Your Organization, (...)
valid from 2024-11-01T12:00:45Z to 2027-11-01T22:59:00Z,
serial-number: xyz123abc456,
issuer: CN=Buypass Class 3 Test4 CA G2 ST Business, O=Buypass AS,
OID.2.5.4.97=NTRNO-983163327, C=NO
is not authorized to access this system
</error-message>
<error-type>CLIENT</error-type>
</error>
(Namespaces and other XML-related formalities omitted for brevity)
Your enterprise certificate has been successfully validated as authentic, but the organization number the certificate is issued to has not been authorized to use the API on behalf of the organization number in the request URL.
<error>
<error-code>BROKER_NOT_AUTHORIZED<error-code>
<error-message>
Broker «[organization number], authenticated using certificate
OID.2.5.4.97=NTRNO-[organization number], CN=Your Organization, (...)
valid from 2024-11-01T12:00:45Z to 2027-11-01T22:59:00Z,
serial-number: xyz123abc456,
issuer: CN=Buypass Class 3 Test4 CA G2 ST Business, O=Buypass AS,
OID.2.5.4.97=NTRNO-983163327, C=NO»
is not authorized to send on behalf of «[organization number from request URL]»
</error-message>
<error-type>CLIENT</error-type>
</error>
(Namespaces and other XML-related formalities omitted for brevity)
If your certificate was not accepted for establishing the TLS connection, an error like this will be issued by curl:
curl: (56) LibreSSL SSL_read: LibreSSL/3.3.6: error:1404C416:SSL
routines:ST_OK:sslv3 alert certificate unknown, errno 0
You need to check the certificate you are using, and verify it is indeed a proper enterprise certificate, and you are using the certificate applicable for the environment you are trying to reach, i.e. test certificates are used for the API in our public test environment, and your production certificate is used for the API in production at api.signering.posten.no.
If you are missing authorization for the API, please contact us.
.NET Core
Enabling logging
The client library has the ability to log useful information that can be used for debug purposes. To enable logging, supply the Direct or Portal client with an implementation of Microsoft.Extensions.Logging.ILoggerFactory. This is Microsoft’s own logging API, and allows the user to chose their own logging framework.
Enabling logging on level DEBUG will output positive results of requests and worse, WARN only failed requests or worse, while ERROR will only occur on failed requests to create a signature job. These loggers will be under the Digipost.Signature.Api.Client namespace.
Implementing using NLog
There are numerous ways to implement a logger, but the following examples will be based on NLog documentation.
Install the Nuget-packages
NLog,NLog.Extensions.LoggingandMicrosoft.Extensions.DependencyInjection.Create a nlog.config file. The following is an example that logs to file and to console:
<?xml version="1.0" encoding="utf-8"?>
<!-- XSD manual extracted from package NLog.Schema: https://www.nuget.org/packages/NLog.Schema-->
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xsi:schemaLocation="NLog NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
autoReload="true"
internalLogFile="c:\temp\console-example-internal.log"
internalLogLevel="Info">
<!-- the targets to write to -->
<targets>
<!-- write logs to file -->
<target xsi:type="File"
name="fileTarget"
fileName="/logs/signature-api-client-dotnet/signature-api-client-dotnet.log"
layout="${date}|${level:uppercase=true}|${message} ${exception}|${logger}|${all-event-properties}"
archiveEvery="Day"
archiveNumbering="Date"
archiveDateFormat="yyyy-MM-dd"/>
<!-- write logs to console -->
<target xsi:type="Console"
name="consoleTarget"
layout="${date}|${level:uppercase=true}|${message} ${exception}|${logger}|${all-event-properties}" />
</targets>
<!-- rules to map from logger name to target -->
<rules>
<logger name="*" minlevel="Trace" writeTo="fileTarget,consoleTarget"/>
</rules>
</nlog>
In your application, do the following to create a logger and supply it to the client:
private static IServiceProvider CreateServiceProviderAndSetUpLogging()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory, LoggerFactory>();
services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
services.AddLogging((builder) => builder.SetMinimumLevel(LogLevel.Trace));
var serviceProvider = services.BuildServiceProvider();
SetUpLoggingForTesting(serviceProvider);
return serviceProvider;
}
private static void SetUpLoggingForTesting(IServiceProvider serviceProvider)
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
loggerFactory.AddNLog(new NLogProviderOptions {CaptureMessageTemplates = true, CaptureMessageProperties = true});
NLog.LogManager.LoadConfiguration("./nlog.config");
}
static void Main(string[] args)
{
ClientConfiguration clientConfiguration = null;
var serviceProvider = CreateServiceProviderAndSetUpLogging();
var client = new PortalClient(clientConfiguration, serviceProvider.GetService<ILoggerFactory>());
}
Request and response logging
For initial integration and debugging purposes, it can be useful to log the actual request and response going over the wire. This can be enabled by doing the following:
Set the property ClientConfiguration.LogRequestAndResponse = true.
Caution
Enabling request logging should never be used in a production system. It will severely impact the performance of the client.
Logging of document bundle
Logging of document bundle can be enabled via the ClientConfiguration:
var clientConfiguration = new ClientConfiguration(Environment.DifiTest, "3k 7f 30 dd 05 d3 b7 fc...");
clientConfiguration.EnableDocumentBundleDiskDump("/directory/path/for/bundle/disk/dump");
Note
Remember to only set the directory to save the disk dump. A new zip file will be placed there for each created signature job.
If you have special needs for the bundle other than just saving it to disk, add your own bundle processor to ClientConfiguration.DocumentBundleProcessors.
Java
Request and response logging
Caution
Enabling request logging should never be used in a production system. It will impact the performance of the client.
You may configure the client library to log HTTP requests and responses by calling .enableRequestAndResponseLogging() when creating the client’s configuration. You may configure the logger no.digipost.signature.client.http.requestresponse in order to customize logging. It must be set to at least INFO to write anything to the log.
Writing document bundle to disk
You may configure the client library to write a ZIP file with the document bundle by calling .enableDocumentBundleDiskDump(Path) when creating the client’s configuration.
The Path parameter is the directory to where the files will be written. This directory must exists as the client library won’t try creating it.
If you have needs for the document bundle other than just saving it to disk, add your own document bundle processor by calling .addDocumentBundleProcessor(…) with your own DocumentBundleProcessor when creating the client’s configuration.