Quantcast
Channel: Magnus K Karlsson
Viewing all 526 articles
Browse latest View live

Eclipse Microprofile and Java EE 8 with JBoss EAP 7.2

$
0
0

The Eclipse Microprofile is a spin of from Java EE and is a fast pace standardization community for building standardized Microservices. There are several subprojects within Microprofile and there are constantly more added all the time. To see all full list visit https://microprofile.io/projects/.

To get started to use Eclipse Microprofile you simple add the maven dependency org.eclipse.microprofile:microprofile.

Before using Eclipse Microprofile, you must first check which version your Java Container supports, alternative you can packages the binaries inside your web application.

For JBoss EAP 7.2 it does not support the entire Eclipse Microprofile version 1.4, but a subset of it. To get started use the following pom.xml.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<groupId>se.magnuskkarlsson.examples</groupId>
<artifactId>javaee8-microprofile1.4-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.outputEncoding>UTF-8</project.build.outputEncoding>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>1.4</version>
<type>pom</type>
<scope>provided</scope>
</dependency>

<!-- Test Support -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>11</release>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
</plugins>
</build>
</project>

And the src/main/webapp/WEB-INF/web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

</web-app>

And the src/main/webapp/WEB-INF/beans.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
version="2.0" bean-discovery-mode="all">

</beans>

And the src/main/resources/META-INF/persistence.xml


<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">

<persistence-unit name="PROD"></persistence-unit>
</persistence>

Eclipse Microprofile Configuration with Java EE 8 and JBoss EAP 7.2

$
0
0

Here we are going to look at Eclipse Microprofile Configuration with Java EE 8 and JBoss EAP 7.2.

The configuration project is a convenient project to easily load configuration from:

  • System Property, e.g. -Dnum.size=20
  • Properties file, e.g. configuration.properties

To get started we use the previous blog project setup, with pom.xml, web.xml, beans.xml and persistence.xml. Please see https://magnus-k-karlsson.blogspot.com/2019/10/eclipse-microprofile-and-java-ee-8-with.html.

And the injection configuration:


package se.magnuskkarlsson.example.microprofile.boundary;

import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.microprofile.config.inject.ConfigProperty;

@Path("/persons")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

@Inject
@ConfigProperty(name = "num.size", defaultValue = "12")
int numSize;

@GET
public Response hello() {
JsonObject json = Json.createObjectBuilder().add("message", "HELLO " + numSize).build();
return Response.ok(json.toString()).build();
}

}

And to make JAX-RS complete we also need


package se.magnuskkarlsson.example.microprofile;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rest")
public class JAXRSApplication extends Application {

}

Now we can build and deploy the web application. To configure we have now two options

  • System Properties, e.g. ./standalone.sh -Dnum.size=20
  • Property File, e.g. ./standalone.sh -P ../standalone/configuration/configuration.properties

Test both ways, but for production, property file is the recommended way.

Eclipse Microprofile Health with Java EE 8 and JBoss EAP 7.2

$
0
0

In my previous blogs we have layed out a maven project for Eclipse Microprofile and tested Eclipse Microprofile Configuration.

In this blog we will test Eclipse Microprofile Health with JBoss EAP 7.2. First all Eclipse Microprofile in JBoss EAP 7.2 are "Technology Previews only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs)". [https://access.redhat.com/documentation/en-us/red_hat_jboss_enterprise_application_platform/7.2/html-single/configuration_guide/index#microprofile_health_check]

"By default, the MicroProfile Health SmallRye subsystem only examines if the server is running."

You can invoke/call Health in two ways. Through CLI or HTTP.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
"outcome" =>"success",
"result" => {
"outcome" =>"UP",
"checks" => []
}
}

The HTTP endpoint is only exposed through the management interface. "The default address for the /health endpoint, accessible from the management interfaces, is http://127.0.0.1:9990/health."

And also there is not much of configuration you can do.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:read-resource-description(recursive=true, inherited=true)
{
"outcome" =>"success",
"result" => {
"description" =>"WildFly Extension for Eclipse MicroProfile Health With SmallRye",
"capabilities" => [
{
"name" =>"org.wildfly.extension.microprofile.health.smallrye",
"dynamic" => false
},
{
"name" =>"org.wildlfy.microprofile.health.reporter",
"dynamic" => false
}
],
"attributes" => {"security-enabled" => {
"type" => BOOLEAN,
"description" =>"True if authentication is required to access the HTTP endpoint on the HTTP management interface.",
"expressions-allowed" => true,
"required" => false,
"nillable" => true,
"default" => true,
"access-type" =>"read-write",
"storage" =>"configuration",
"restart-required" =>"all-services"
}},
"operations" => undefined,
"notifications" => undefined,
"children" => {}
}
}

This is all not that exciting. But what is when you start to write application specific health check. You do that by implementing org.eclipse.microprofile.health.HealthCheck and annotating class with org.eclipse.microprofile.health.Health.

The best practice is to implement a specific health check in a separate class and then will jboss global health check aggregates all the result from each health check to the overall health check result. So lets start to write a JPA health check.


package se.magnuskkarlsson.example.microprofile;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

@Health
@ApplicationScoped
public class JPAHealthCheck implements HealthCheck {

private final Logger log = Logger.getLogger(JPAHealthCheck.class.getName());

@PersistenceContext
protected EntityManager em;

@Override
public HealthCheckResponse call() {
Integer result = null;
try {
result = (Integer) em.createNativeQuery("SELECT 1").getSingleResult();
} catch (Exception e) {
log.log(Level.SEVERE, "Failed to perform JPA health check.", e);
}
boolean state = (result == 1) ? true : false;
return HealthCheckResponse.named("jpa-health-check").withData("SELECT 1", result).state(state).build();
}

}

Build, deploy and test.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
"outcome" =>"success",
"result" => {
"outcome" =>"UP",
"checks" => [{
"name" =>"health-test",
"state" =>"UP",
"data" => {"JPA 'SELECT 1'" =>"1"}
}]
}
}

Now build a second health check for disk space, but here we will deliberate hard code the output state to down, to test jboss aggregated state value.


package se.magnuskkarlsson.example.microprofile;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;

import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

@Health
@ApplicationScoped
public class DiskSpaceHealthCheck implements HealthCheck {

private final Logger log = Logger.getLogger(DiskSpaceHealthCheck.class.getName());

@Override
public HealthCheckResponse call() {
File path = new File("/");
long diskFreeInBytes = 0L;
try {
diskFreeInBytes = path.getUsableSpace();
} catch (Exception e) {
log.log(Level.SEVERE, "Failed to perform disk space health check.", e);
}
boolean state = false;
return HealthCheckResponse.named("disk-space-health-check").withData(path.getAbsolutePath(), diskFreeInBytes)
.state(state).build();
}

}

Build, deploy and test.


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check
{
"outcome" =>"success",
"result" => {
"outcome" =>"DOWN",
"checks" => [
{
"name" =>"jpa-health-check",
"state" =>"UP",
"data" => {"SELECT 1" => 1}
},
{
"name" =>"disk-space-health-check",
"state" =>"DOWN",
"data" => {"/" => 409898860544L}
}
]
}
}

As you can see the overall state is DOWN.

To get more inspiration for others health check, see spring boots health indicators - https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/health/AbstractHealthIndicator.html

And finally it is of interest to read the Eclipse Microprofile Health Specification.

Eclipse Microprofile OpenTracing with Java EE 8 and JBoss EAP 7.2

$
0
0

MicroProfile OpenTracing

"The MicroProfile OpenTracing specification defines behaviors and an API for accessing an OpenTracing compliant Tracer object within your JAX-RS application. The behaviors specify how incoming and outgoing requests will have OpenTracing Spans automatically created." [https://microprofile.io/project/eclipse/microprofile-opentracing]

JBoss EAP 7.2

"SmallRye OpenTracing component and is provided by the microprofile-opentracing-smallrye subsystem."

"This subsystem implements Microprofile 1.1, which includes support for tracing requests to JAX-RS endpoints and CDI beans and is included in the default JBoss EAP 7.2 configuration."

"The microprofile-opentracing-smallrye subsystem ships with the Jaeger Java Client as the default tracer"

"Each individual WAR deployed to the JBoss EAP server automatically has its own Tracer instance."

"Instead, you configure the Jaeger Client by setting system properties or environment variables. See the Jaeger documentation [1] for information about how to configure the Jaeger Client. See Configuration via Environment [2] in the Jaeger documentation for the list of valid system properties."

"Because this feature is provided as Technology Preview, the current configuration options, particularly those related to configuring the Jaeger Java Client tracer using system properties and environment variables, might change in incompatible ways in future releases."

[JBoss EAP 7.2 Configuration Guide Eclipse Microprofile OpenTracing]

The microprofile-opentracing-smallrye subsystem does not offer any configuration in JBoss EAP 7.2


/subsystem=microprofile-opentracing-smallrye:read-resource-description(recursive=true)
{
"outcome" =>"success",
"result" => {
"description" =>"Wildfly Extension for Eclipse MicroProfile OpenTracing With SmallRye",
"attributes" => {},
"operations" => undefined,
"notifications" => undefined,
"children" => {}
}
}

Jaeger

See https://www.jaegertracing.io/.

Jaeger Openshift Template

See https://github.com/jaegertracing/jaeger-openshift. To run, run below command.


$ oc process -f https://raw.githubusercontent.com/jaegertracing/jaeger-openshift/master/all-in-one/jaeger-all-in-one-template.yml | oc create -f -

Jaeger Docker Image

But we are going to run the all-in-one docker image, see https://hub.docker.com/r/jaegertracing/all-in-one

To install Docker, see http://magnus-k-karlsson.blogspot.com/2019/08/install-docker-community-edition-ce-on.html.

Source code (Dockerfile) https://github.com/jaegertracing/jaeger/blob/master/cmd/all-in-one/Dockerfile

To run


$ docker run -d -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 14268:14268 -p 14250:14250 -p 16686:16686 jaegertracing/all-in-one

Web Application

Now we are going to write our application, use Java EE 8 and Eclipse Microprofile 1.4 from http://magnus-k-karlsson.blogspot.com/2019/10/eclipse-microprofile-and-java-ee-8-with.html.

Now lets write a @Traced JAX-RS endpoint and a CDI bean.


package se.magnuskkarlsson.example.microprofile.boundary;

import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.eclipse.microprofile.opentracing.Traced;

import se.magnuskkarlsson.example.microprofile.control.PersonService;

@Traced
@Path("/persons")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

@Inject
protected PersonService personService;

@GET
public Response hello() {
JsonObject json = Json.createObjectBuilder().add("message", personService.getMessage()).build();
return Response.ok(json.toString()).build();
}

}

package se.magnuskkarlsson.example.microprofile.control;

import org.eclipse.microprofile.opentracing.Traced;

@Traced
public class PersonService {

public String getMessage() {
return "HELLO " + System.currentTimeMillis();
}

}

Also see JBoss EAP 7.2 Development Guide Eclipse Microprofile OpenTracing

Now we need Jaeger client configuration, configuration.properties


JAEGER_SERVICE_NAME=magnuskkarlsson
JAEGER_ENDPOINT=http://127.0.0.1:14268/api/traces
JAEGER_SAMPLER_TYPE=const
JAEGER_SAMPLER_PARAM=1

Build, deploy and start JBoss EAP 7.2 with above configuration file.


$ ./standalone.sh -P /home/magnuskkarlsson/eclipse-workspace/javaee8-microprofile1.4-example/configuration.properties
...
20:06:17,308 DEBUG [io.jaegertracing.thrift.internal.senders.ThriftSenderFactory] (ServerService Thread Pool -- 72) Using the HTTP Sender to send spans directly to the endpoint.
20:06:17,409 DEBUG [io.jaegertracing.internal.senders.SenderResolver] (ServerService Thread Pool -- 72) Using sender HttpSender()
20:06:17,417 INFO [io.jaegertracing.Configuration] (ServerService Thread Pool -- 72) Initialized tracer=JaegerTracer(version=Java-0.30.6.redhat-00001, serviceName=magnuskkarlsson, reporter=RemoteReporter(sender=HttpSender(), closeEnqueueTimeout=1000), sampler=ConstSampler(decision=true, tags={sampler.type=const, sampler.param=true}), tags={hostname=localhost.localdomain, jaeger.version=Java-0.30.6.redhat-00001, ip=127.0.0.1}, zipkinSharedRpcSpan=false, expandExceptionLogs=false)
...

Now open web application and make a few requests http://localhost:8080/javaee8-microprofile1.4-example/rest/persons.

Now lets see if those traces are sent to Jaeger, open http://127.0.0.1:16686/search

Eclipse Microprofile Metrics with Wildfly 18 and Prometheus

$
0
0

Eclipse Microprofile Metrics

"This specification aims at providing a unified way for Microprofile servers to export Monitoring data ("Telemetry") to management agents and also a unified Java API, that all (application) programmers can use to expose their telemetry data." [https://microprofile.io/project/eclipse/microprofile-metrics]

Source code https://github.com/eclipse/microprofile-metrics/

Eclipse Microprofile Metrics Specification https://github.com/eclipse/microprofile-metrics/releases

JBoss EAP 7.2

Does not support Eclipse Microprofile Metrics.

Wildfly 18.0.0.Final

Wildfly 18.0.0.Final supports Eclipse Microprofile Metrics 2.0.0 [1], which is part of Eclipse Microprofile 3.0.

[1] $JBOSS_HOME/modules/system/layers/base/org/eclipse/microprofile/metrics/api/main/microprofile-metrics-api-2.0.2.jar

Documentation https://docs.wildfly.org/18/Admin_Guide.html#MicroProfile_Metrics_SmallRye

Configuration


[standalone@localhost:9990 /] /subsystem=microprofile-metrics-smallrye:read-resource(recursive=true, include-defaults=true)
{
"outcome" =>"success",
"result" => {
"exposed-subsystems" => ["*"],
"prefix" => expression "${wildfly.metrics.prefix:wildfly}",
"security-enabled" => false
}
}

Wildfly exposes Metrics via HTTP Management Interface, i.e. http://127.0.0.1:9990/metrics.

Prometheus

Prometheus is an open-source monitoring and alerting platform. Its main features are:

  • "Prometheus implements a highly dimensional data model. Time series are identified by a metric name and a set of key-value pairs."
  • "PromQL allows slicing and dicing of collected time series data in order to generate ad-hoc graphs, tables, and alerts."
  • "Prometheus has multiple modes for visualizing data: a built-in expression browser, Grafana integration, and a console template language."
  • "Prometheus stores time series in memory and on local disk in an efficient custom format. Scaling is achieved by functional sharding and federation."
  • "Each server is independent for reliability, relying only on local storage. Written in Go, all binaries are statically linked and easy to deploy."
  • "Alerts are defined based on Prometheus's flexible PromQL and maintain dimensional information. An alertmanager handles notifications and silencing."
  • "Client libraries allow easy instrumentation of services. Over ten languages are supported already and custom libraries are easy to implement."
  • "Existing exporters allow bridging of third-party data into Prometheus. Examples: system statistics, as well as Docker, HAProxy, StatsD, and JMX metrics."

[https://prometheus.io/]

Prometheus can either be locally installed or via Docker.

For local installation, download latest Prometheus version unpack it and run './prometheus'.

To use Docker, use Prometheus Image at https://hub.docker.com/r/prom/prometheus.

Prometheus Docker Image source (Dockerfile) https://github.com/prometheus/prometheus/blob/master/Dockerfile.

Prometheus Docker Image documentation https://prometheus.io/docs/prometheus/latest/installation/.

Before we can use Prometheus for Wildfly we need to add Wildfly metrics endpoint to Prometheus configuration. First download Prometheus and edit prometheus.yml in the root of the zipped installation.


# my global config
global:
scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label `job=` to any timeseries scraped from this config.
- job_name: 'prometheus'

# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.

static_configs:
- targets: ['localhost:9090']

# this is the configuration to poll metrics from WildFly 18
# https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config
- job_name: 'wildfly18'
scrape_interval: 2s
metrics_path: '/metrics'
scheme: 'http'
static_configs:
- targets: ['127.0.0.1:9990']

Then start Prometheus with './prometheus', then open http://127.0.0.1:9090/. To test it check which metrics wildfly is exposing, by calling it metrics endpoint.


$ curl http://127.0.0.1:9990/metrics

# HELP base_cpu_processCpuLoad Displays the "recent cpu usage" for the Java Virtual Machine process.
# TYPE base_cpu_processCpuLoad gauge
base_cpu_processCpuLoad 1.5940700593791097E-4

Go back to Prometheus and enter base_cpu_processCpuLoad.

Eclipse Microprofile Metrics and Application Metrics with Wildfly 18

$
0
0

Introduction

In my previous blog Eclipse Microprofile Metrics with Wildfly 18 and Prometheus, we were getting started with Eclipse Microprofile Metrics and Wildfly 18.

All Metrics: http://127.0.0.1:9990/metrics

Basic Metrics: http://127.0.0.1:9990/metrics/base

Vendor Specific Metrics: http://127.0.0.1:9990/metrics/vendor

Application Specific Metrics: http://127.0.0.1:9990/metrics/application

And in this blog we will focus how to write application specific metrics. Eclipse Microprofile Metrics is by default active in Wildfly 18, so no activation or configurations are needed. The application is a standard Java EE 8 web application with JAX-RS.

For documentation see Metrics Specification https://github.com/eclipse/microprofile-metrics/releases

@Counted

The @Counted annotation which counts how many time a request has been made.


@GET
@Path("/firstName")
@Counted
public Response getFirstName() {
JsonObject json = Json.createObjectBuilder().add("@Counted", "HELLO " + System.currentTimeMillis()).build();
return Response.ok(json.toString()).build();
}

# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getFirstName_total counter
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getFirstName_total 1.0

@Gauge

The @Gauge is the most basic metric type that you can use as it just returns a value.


@GET
@Path("/time")
@Produces(MediaType.TEXT_PLAIN)
@Gauge(unit = "time")
public Long getTime() {
return System.currentTimeMillis();
}

# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTime_time gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTime_time 1.571012533582E12

@Metered

The @Metered annotation measures the rate at which a set of events occur.


@GET
@Path("/title")
@Metered(unit = MetricUnits.MILLISECONDS)
public Response getTitle() {
JsonObject json = Json.createObjectBuilder().add("@Metered", "HELLO " + System.currentTimeMillis()).build();
return Response.ok(json.toString()).build();
}

# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_total counter
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_total 2.0
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_rate_per_second 0.10850140606928724
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_one_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_one_min_rate_per_second 0.030703655021877174
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_five_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_five_min_rate_per_second 0.0065567799035988195
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_fifteen_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getTitle_fifteen_min_rate_per_second 0.002209922141215539

@Timed

The @Timed annotatoin measures the duration of an event.


@GET
@Path("/occupation")
@Timed(unit = MetricUnits.MILLISECONDS)
public Response getOccupation() {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
JsonObject json = Json.createObjectBuilder().add("@Timed", "HELLO " + System.currentTimeMillis()).build();
return Response.ok(json.toString()).build();
}

# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_rate_per_second 0.10850160127626114
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_one_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_one_min_rate_per_second 0.031982234148270686
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_five_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_five_min_rate_per_second 0.0066114184713530035
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_fifteen_min_rate_per_second gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_fifteen_min_rate_per_second 0.0022160607980413085
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_min_seconds gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_min_seconds 0.326822982
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_max_seconds gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_max_seconds 0.492277962
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_mean_seconds gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_mean_seconds 0.4076894175173451
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_stddev_seconds gauge
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_stddev_seconds 0.08270655402029932
# TYPE application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds summary
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds_count 2.0
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.5"} 0.326822982
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.75"} 0.492277962
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.95"} 0.492277962
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.98"} 0.492277962
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.99"} 0.492277962
application_se_magnuskkarlsson_example_microprofile_boundary_PersonResource_getOccupation_seconds{quantile="0.999"} 0.492277962

JSON Output

You can also query the application metrics with accept type json.


$ curl -H "Accept: application/json" http://127.0.0.1:9990/metrics/application

{
"se.magnuskkarlsson.example.microprofile.boundary.PersonResource.getTitle": {
"fiveMinRate": 0.004020212971829918,
"fifteenMinRate": 0.0021635871943593244,
"meanRate": 0.00440791116923509,
"count": 3,
"oneMinRate": 0.015991588875909905
},
"se.magnuskkarlsson.example.microprofile.boundary.PersonResource.getMiddleName": {
"current": 0,
"min": 0,
"max": 0
},
"se.magnuskkarlsson.example.microprofile.boundary.PersonResource.getOccupation": {
"p99": 928.815422,
"min": 326.822982,
"max": 928.815422,
"mean": 928.7665329420207,
"p50": 928.815422,
"p999": 928.815422,
"stddev": 5.110449494753552,
"p95": 928.815422,
"p98": 928.815422,
"p75": 928.815422,
"fiveMinRate": 0.0040261670318063715,
"fifteenMinRate": 0.0021665192890272054,
"meanRate": 0.004407906126221853,
"count": 3,
"oneMinRate": 0.01599160852294868
},
"se.magnuskkarlsson.example.microprofile.boundary.PersonResource.getFirstName": 3
}

How to Read MSUPN in X509Certificate

$
0
0

Maven dependency


<!-- The prov module provides all the JCA/JCE provider functionality. -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!-- The pkix module is the home for code for X.509 certificate generation
and the APIs for standards that rely on ASN.1 such as CMS, TSP, PKCS#12, OCSP, CRMF,
and CMP. -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>

The source code for The Bouncy Castle Crypto Package For Java.

The Java code


package se.magnuskkarlsson.example.bouncycastle;

import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;

import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.asn1.x509.GeneralName;

public class X509CertificateUtils {

public static final String MSUPN_OID = "1.3.6.1.4.1.311.20.2.3";
private final Logger log = Logger.getLogger(X509CertificateUtils.class.getName());

public String getMSUPNFromX509Certificate(X509Certificate cert) throws CertificateParsingException {
Collection<List<?>> sans = JcaX509ExtensionUtils.getSubjectAlternativeNames(cert);
for (List<?> san : sans) {

log.info("Read X509 SAN " + sans);
int sanType = (int) san.get(0);
if (sanType == GeneralName.otherName) {

ASN1Sequence sanASN1Sequence = (ASN1Sequence) san.get(1);
String msupn = getSANFromASN1Sequence(sanASN1Sequence);
if (msupn != null) {
return msupn;
}
}
}
return null;
}

private String getSANFromASN1Sequence(ASN1Sequence sanASN1Sequence) {
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) sanASN1Sequence.getObjectAt(0);
if (!MSUPN_OID.equals(oid.getId())) {
log.warning("Invalid MSUPN OID, expected '" + MSUPN_OID + "' got '" + oid.getId() + "'.");
return null;
}

ASN1TaggedObject sanASN1TaggedObject = (ASN1TaggedObject) sanASN1Sequence.getObjectAt(1);
ASN1Primitive sanASN1Primitive = sanASN1TaggedObject.getObject();

if (sanASN1Primitive instanceof ASN1String) {
return ((ASN1String) sanASN1Primitive).getString();
}
log.warning("Invalid ASN.1 Primitive class, expected ASN1String, got " + sanASN1Primitive.getClass());
return null;
}

}

How To Install VisualVM on Fedora 30 and OpenJDK 11


Eclipse Microprofile LDAP Health Check with Java EE 8 and JBoss EAP 7.2

$
0
0

Introduction

In my previous blog I wrote about Eclipse Microprofile Health with Java EE 8 and JBoss EAP 7.2 and pointed to several Health Checks built in Spring, but for LDAP Springs Health Check is not very good. A better implementation is suggested below. And also based on standard Eclipse Microprofile Health.

Eclipse Microprofile LDAP Health Check


package se.magnuskkarlsson.example.microprofile;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;

import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

@Health
@ApplicationScoped
public class LDAPHealthCheck implements HealthCheck {

private final Logger log = Logger.getLogger(LDAPHealthCheck.class.getName());

@Inject
@ConfigProperty(name = "ldapHealthCheck.providerURL")
protected String providerURL;

@Inject
@ConfigProperty(name = "ldapHealthCheck.securityPrincipal")
protected String securityPrincipal;

@Inject
@ConfigProperty(name = "ldapHealthCheck.securityCredentials")
protected String securityCredentials;

@Inject
@ConfigProperty(name = "ldapHealthCheck.baseCtxDN")
protected String baseCtxDN;

@PostConstruct
public void init() {
}

@Override
public HealthCheckResponse call() {
List<String> result = null;
try {
result = searchBaseContextDN();
} catch (Exception e) {
log.log(Level.SEVERE, "Failed to perform LDAP health check search baseCtxDN='" + baseCtxDN + "'.", e);
}
boolean state = (result != null && !result.isEmpty()) ? true : false;
String data = (result != null && !result.isEmpty()) ? result.toString() : null;
return HealthCheckResponse.named("ldap-health-check").withData(baseCtxDN, data).state(state).build();
}

protected List<String> searchBaseContextDN() throws NamingException {
InitialLdapContext ctx = null;
try {
Properties env = new Properties();
env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.setProperty(Context.PROVIDER_URL, providerURL);
env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
env.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal);
env.put(Context.SECURITY_CREDENTIALS, securityCredentials);

log.info("Logging into LDAP server, env=" + env);
ctx = new InitialLdapContext(env, null);
log.info("Logged into LDAP server, " + ctx);

// filter
String filter = "(objectClass=*)";

// scope
SearchControls ctls = new SearchControls();
ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);

// search for objects using filter and scope
NamingEnumeration<SearchResult> answer = ctx.search(baseCtxDN, filter, ctls);
List<String> result = new ArrayList<String>();
while (answer.hasMore()) {
SearchResult searchResult = answer.next();
if (searchResult != null) {
result.add(searchResult.toString());
}
}

log.info("Result base context dn, " + result);
return result;
} finally {
if (ctx != null) {
try {
// Close the context when we're done
ctx.close();
} catch (NamingException IGNORE) {
}
}
}
}

}

Test

http://127.0.0.1:9990/health


[standalone@localhost:9990 /] /subsystem=microprofile-health-smallrye:check

How to Install IDM Master and Replica on RHEL 7

$
0
0

Minimum Hardware

4 GB RAM

https://bugzilla.redhat.com/show_bug.cgi?id=1436295

Prerequisite

I have created two virtual machine, since this is a development setup I will hardcode hostname and IP in /etc/hosts and manually set hostnames.

  • rhel7.7-idm-master.magnuskkarlsson.local
    • 192.168.122.113
  • rhel7.7-idm-replica1.magnuskkarlsson.local
    • 192.168.122.99

# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.7 (Maipo)

# systemctl stop firewalld; systemctl disable firewalld

# hostnamectl set-hostname rhel7.7-idm-master.magnuskkarlsson.local
# hostnamectl set-hostname rhel7.7-idm-replica1.magnuskkarlsson.local

# echo "192.168.122.113 rhel7.7-idm-master.magnuskkarlsson.local">> /etc/hosts
# echo "192.168.122.99 rhel7.7-idm-replica1.magnuskkarlsson.local">> /etc/hosts

Update Date & Time

Make sure NTP is setup and synchronized.


systemctl restart chronyd
chronyc sources
chronyc tracking
timedatectl

Installation of IDM Master (version 4.6.5)

Install IDM Master on rhel7.7-idm-master.magnuskkarlsson.local.


# yum install -y ipa-server

# ipa-server-install --domain magnuskkarlsson.local \
--realm MAGNUSKKARLSSON.LOCAL \
-p foo123123 -a foo123123 -U

Installation of IDM Replica (version 4.6.5)

Install IDM Replica on rhel7.7-idm-replica1.magnuskkarlsson.local.

First install idm/ipa client and register host in idm. Then setup host as replica.


# yum install -y ipa-server

# ipa-client-install --server=rhel7.7-idm-master.magnuskkarlsson.local \
--domain=magnuskkarlsson.local \
--principal=admin \
--password=foo123123 -U

# ipa-replica-install --setup-ca --principal=admin --admin-password=foo123123 -U

Test

First kerberos login on master - rhel7.7-idm-master.magnuskkarlsson.local and add a user.


# kinit admin

# ipa user-add --first="Magnus K" \
--last=Karlsson \
--cn="Magnus K Karlsson" \
--principal=magnuskkarlsson \
--password \
--all magnuskkarlsson

# ipa user-find magnuskkarlsson

Then kerberos login on replica - rhel7.7-idm-replica1.magnuskkarlsson.local and search for user and check that user is replicated.


# kinit admin

# ipa user-find magnuskkarlsson

Introduction to YAML

$
0
0

Introduction

The YAML format has grown in popularity and is used for example in Kubernetes and Ansible.

Comparison XML, JSON and YAML

XMLJSONYAML

<Servers>
<Server>
<id>12345</id>
<name>My Web Server</name>
<status>ACTIVE</status>
</Server>
</Servers>

{
"Servers": [
{
"id": "12345",
"name": "My Web Server",
"status": "ACTIVE"
}
]
}

Servers:
- id: 1234
name: My Web Server
status: ACTIVE

Tools for validating JSON

There are numerous tools out that for JSON, one for Linux and Bash is jq - a lightweight and flexible command-line JSON processor.


$ sudo yum install jq

$ cat servers.json | jq '.Servers[0].id'
"12345"

Tools for validating YAML

And a Linux and Bash tool for YAML is yq


$ sudo yum install python3 python3-pip
$ sudo pip3 install yq

$ cat servers.yaml | yq '.'
{
"Servers": [
{
"id": 1234,
"name": "My Web Server",
"status": "ACTIVE"
}
]
}

YAML Data Types

WARNING: YAML is not structured in the same sense as XML, JSON, XHTML, etc. It uses spaces (and not tabs and do not mix space and tabs) as seperator. So pay extra attention to how many spaces you use.

Key Value Pair


Fruit: Orange
Vegetable: Lettuce
Liquid: Wine

$ cat key_value_pair.yaml | yq '.'
{
"Fruit": "Orange",
"Vegetable": "Lettuce",
"Liquid": "Wine"
}

List (Array)


Fruits:
- Orange
- Apple
- Banana

Vegetables:
- Carrot
- Tomatoes
- Onion

$ cat array_list.yaml | yq '.'
{
"Fruits": [
"Orange",
"Apple",
"Banana"
],
"Vegetables": [
"Carrot",
"Tomatoes",
"Onion"
]
}

Dictionary (Map)


Banana:
Calories: 105
Fat: 0.4 g
Carbs: 31 g

Grapes:
Calories: 27
Fat: 0.7 g
Carbs: 56 g

$ cat dictionary_map.yaml | yq '.'
{
"Banana": {
"Calories": 105,
"Fat": "0.4 g",
"Carbs": "31 g"
},
"Grapes": {
"Calories": 27,
"Fat": "0.7 g",
"Carbs": "56 g"
}
}

More Advanced Examples. List of Dictionary (Array of Map)


Fruits:
- Orange:
Calories: 105
Fat: 0.4 g
Carbs: 31 g
- Apple:
Calories: 27
Fat: 0.7 g
Carbs: 56 g

$ cat array_list_of_dictionary_map.yaml | yq '.'

$ cat array_list_of_dictionary_map.yaml | yq '.Fruits[1]'
{
"Apple": {
"Calories": 27,
"Fat": "0.7 g",
"Carbs": "56 g"
}
}

Differences between List and Dictionary

Dictionary - Unordered

List - Ordered

How to Install VirtualBox 6 on Fedora 30

Getting Started with Minikube on Fedora 30

$
0
0

Introduction

To install Minikube there are 3 things to do:

  1. Install a hypervisor, e.g. VirtualBox, KVM
  2. "Install" (download and add in path) kubectl
  3. "Install" (download and add in path) Minikube

Install kubectl

Reference: https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl-on-linux


$ curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl

$ chmod +x ./kubectl

$ sudo mv ./kubectl /usr/local/bin/kubectl

$ kubectl version

Install MiniKube


$ wget https://github.com/kubernetes/minikube/releases/download/v1.6.0-beta.1/minikube-1.6.0.beta.1.rpm .

$ sudo rpm -pi minikube-1.6.0.beta.1.rpm

$ sudo rpm -ql minikube
/usr/bin/minikube

$ sudo rpm -q --scripts minikube

Test

https://kubernetes.io/docs/setup/learning-environment/minikube/

Start Minikube and create a cluster. Here I specify VirtualBox as hypervisor, since I have also KVM installed.


$ minikube start --vm-driver=virtualbox

Deploy image 'k8s.gcr.io/echoserver' version 1.10 and name deployment 'hello-minikube'.


$ kubectl create deployment hello-minikube --image=k8s.gcr.io/echoserver:1.10

Expose deployment on NodePort and port 8080, i.e. create routing.


$ kubectl expose deployment hello-minikube --type=NodePort --port=8080

Check deployment has finished.


$ kubectl get pod

Retrieve internal IP and port and access web app.


$ minikube service hello-minikube --url
http://192.168.99.100:30024

$ curl http://192.168.99.100:30024
Hostname: hello-minikube-797f975945-fmswk

Pod Information:
-no pod information available-

Server values:
server_version=nginx: 1.13.3 - lua: 10008

Request Information:
client_address=172.17.0.1
method=GET
real path=/
query=
request_version=1.1
request_scheme=http
request_uri=http://192.168.99.100:8080/

Request Headers:
accept=*/*
host=192.168.99.100:30024
user-agent=curl/7.65.3

Request Body:
-no body in request-

Tomcat RPM installation on RHEL and CentOS

$
0
0

Introduction

Using a RPM installation from a trusted RPM repository is a huge advantage, since then is life cycle with patching made easy. Otherwise you will have to manage all patching yourself, which in the long run, will always be more costly than using RPM installation from a trusted RPM repository. And you will also be more exposed by security weakness, because you have not a current patched software version.

RHEL 7 and CentoOS 7

Both RHEL 7 and CentOS 7 comes with a ready to use Tomcat 7. The only drawback is that the version is rather old.

But do you really need a newer version? The difference between Servlet 3.0 (part of Java EE 6) and Servlet 4.0 (part of Java EE 8) is quite small.

And if you are using websockets it is the same version of the spec between Tomcat 7 and 9. Other bigger differences is the support for HTTP/2, but do really need this? Maybe you do or you do not. And if you do not use these new feature you are probably fine with an older version of Tomcat.

From a security perspective, the difference between Tomcat 7 and 9 (as long they are patched), are minimal. Alla the security configuration in web.xml are in place in Tomcat 7. See (Mis)Configure web.xml in Java EE 6 . The only new feature in Servlet 4 and web.xml is

  1. default-context-path
  2. request-character-encoding
  3. response-character-encoding
  4. deny-uncovered-http-methods
  5. absolute-ordering (only relevant if you are using web-fragment.xml)

And the difference between security specific feature between Tomcat 7 and 9 are

  1. Tomcat 9 new supports OCSP, but only for Tomcat Native Connector. See https://tomcat.apache.org/tomcat-9.0-doc/ssl-howto.html#Using_OCSP_Certificates
  2. Both Tomcat 7 and 9 both rely on MBean technology for monitoring, which is a problem, since remote JMX connection does not support strong authentication, only username and password and default requires random ports. The random ports can be fixed with catalina-jmx-remote.jar, see Enable JMX Remote in Tomcat 7
  3. Pure Tomcat High Availability (HA) is the same, i.e. 1. replication is the same, but do you really need this, maybe you do or you do not. 2. Pure Tomcat load balancing is seldom used in production. If you are looking for a software solution I recommend using mod_cluster, which works very well. If that is not an option use mod_proxy. Otherwise most people use a hardware load balancer like BigIP F5.
  4. Tomcat 9 still have crazy logging handling. 1. logging to multiple files which make error search hard and general overview of the tomcat health hard. 2. The only project using custom logging handler JULI. Do Java really need another logging framework? Consider using a single log file and Log4J, see Use Log4J in Tomcat 7

Otherwise the good security filter are still the same, such as CORS Filter, CSRF Filter, Expires Filter, Failed Request Filter and HTTP Header Security Filter, see Tomcat 7 Container Provided Filters.

The nest lockout realm, see Tomcat 7 Lockout Realm.

RHEL 8 and CentOS 8

Now too the sad story. Tomcat is no longer available on either RHEL 8 or CentOS 8.

"The Apache Tomcat server has been removed from Red Hat Enterprise Linux. Apache Tomcat is a servlet container for the Java Servlet and JavaServer Pages (JSP) technologies. Red Hat recommends that users requiring a servlet container use the JBoss Web Server."
  1. https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html-single/considerations_in_adopting_rhel_8/index#tomcat-removal_dynamic-programming-languages-web-servers-database-servers
  2. https://forums.centos.org/viewtopic.php?t=71787
  3. https://bugzilla.redhat.com/show_bug.cgi?id=1700823

X.509 Certificate Profiles

$
0
0

Mandatory Fields

Serial Number 
Issuer DN 
Validity 
Subject DN 
Subject Public Key InfoContains key algorithm, size and info.

Certificate Extensions

Basic ContraintsCriticalIf CA or not.
Authority Key Identifier Hash of CA public key.
Subject Key Identifier Hash of public key.
Authority Information Access Contains URL to OCSP and CA certificate.
CRL Distribution Points URL to CRL.
Certificate Policies Organization OID for their certificate policy..
Key UsageCriticalKey usage attribute derived from Extended Key Usage.
Extended Key Usage Typical values are from RFC 5280.
Subject Alternative Names Their are different SAN: DNS (for web servers), email (S-MIME) and UPN (Windows login).

RFC 5280

https://tools.ietf.org/html/rfc5280#section-4.2.1.3

Key Usage:

  • digitalSignature -
  • nonRepudiation -
  • keyEncipherment - "subject public key (e.g. RSA) is used for enciphering private or secret keys"
  • dataEncipherment - "NOTE that the use of this bit is extremely uncommon"
  • keyAgreement - "subject public key is used for key agreement (Diffie-Hellman key)"
  • keyCertSign - "If set then CA bit in the basic constraints extension MUST also be set"
  • cRLSign -

Extended Key Usage:

  • serverAuth - Key Usage may be: digitalSignature, keyEncipherment or keyAgreement
  • clientAuth - Key Usage may be: digitalSignature and/or keyAgreement
  • codeSigning - Key Usage may be: digitalSignature
  • emailProtection - Key Usage may be: digitalSignature, nonRepudiation, and/or (keyEncipherment or keyAgreement)
  • timeStamping - Key Usage may be: digitalSignature and/or nonRepudiation
  • OCSPSigning - Key Usage may be: digitalSignature and/or nonRepudiation

EJBCA CE ROOT CA


Basic Constraints - CRITICAL

CA:TRUE

Path Length Constraint: Unlimited

Authority Key ID

Subject Key ID

Key Usage - CRITICAL:
digitalSignature
keyCertSign
cRLSign

Extended Key Usage:
-

Dogtag caCert


https://github.com/dogtagpki/pki/blob/master/base/ca/shared/conf/caCert.profile

Basic Constraints - CRITICAL

CA:TRUE

Path Length Constraint: Unlimited

Authority Key ID

Subject Key ID

Key Usage - CRITICAL:
digitalSignature
nonRepudiation
keyCertSign
cRLSign

Extended Key Usage:
-

EJBCA CE SERVER


Basic Constraints - CRITICAL

Authority Key ID

Subject Key ID

Key Usage - CRITICAL:
digitalSignature
keyEncipherment

Extended Key Usage:
serverAuth

Dogtag rsaServerCert


https://github.com/dogtagpki/pki/blob/master/base/ca/shared/conf/rsaServerCert.profile

Authority Key ID

Key Usage - CRITICAL:
digitalSignature
dataEncipherment
keyEncipherment

Extended Key Usage:
serverAuth

EJBCA CE END USER


Basic Constraints - CRITICAL

Authority Key ID

Subject Key ID

Key Usage - Critical:
digitalSignature
nonRepudiation
keyEncipherment

Extended Key Usage:
clientAuth
emailProtection

Dogtag rsaSubsystemCert


https://github.com/dogtagpki/pki/blob/master/base/ca/shared/conf/rsaSubsystemCert.profile

Authority Key ID

Key Usage - Critical:
digitalSignature
nonRepudiation
dataEncipherment
keyEncipherment

Extended Key Usage:
clientAuth

EJBCA CE OCSP


Basic Constraints - CRITICAL

Authority Key ID

Subject Key ID

Key Usage - CRITICAL:
digitalSignature

Extended Key Usage:
OCSPSigning

OCSP No Check

Dogtag caOCSPCert


https://github.com/dogtagpki/pki/blob/master/base/ca/shared/conf/caOCSPCert.profile

Basic Constraints - CRITICAL

Authority Key ID

Subject Key ID

Key Usage:
-

Extended Key Usage:
OCSPSigning

com.netscape.cms.profile.def.OCSPNoCheckExtDefault

Creating X509 Certificate with Bouncy Castle

$
0
0

Bouncy Castle has X509 Certificate builder but in my opinion it is still quite low tech.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.util.Calendar;
import java.util.Date;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.asn1.x509.Time;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;

// org.bouncycastle.cert.X509v3CertificateBuilder
public class X509CertificateBuilder {

public static final ASN1ObjectIdentifier MSUPN_OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.311.20.2.3");

private V3TBSCertificateGenerator tbsGen;
private ExtensionsGenerator extGenerator;

public X509CertificateBuilder() {
this.tbsGen = new V3TBSCertificateGenerator();
this.extGenerator = new ExtensionsGenerator();
}

// ----------------------- Logic Methods -----------------------

//
// Mandatory Fields
//

public X509CertificateBuilder setSerialNumber(BigInteger serialNumber) {
tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
return this;
}

public X509CertificateBuilder setIssuerDN(X500Name issuerDN) {
this.tbsGen.setIssuer(issuerDN);
return this;
}

public X509CertificateBuilder setValidity(int numberOfYears) {
Date validityNotBefore = new Date(System.currentTimeMillis());
Calendar calendar = Calendar.getInstance();
calendar.setTime(validityNotBefore);
// calendar.add(Calendar.DAY_OF_YEAR, numberOfYears);
calendar.add(Calendar.YEAR, numberOfYears);
Date validityNotAfter = calendar.getTime();
this.tbsGen.setStartDate(new Time(validityNotBefore));
this.tbsGen.setEndDate(new Time(validityNotAfter));
return this;
}

public X509CertificateBuilder setSubjectDN(X500Name subjectDN) {
this.tbsGen.setSubject(subjectDN);
return this;
}

public X509CertificateBuilder setSubjectPublicKeyInfo(PublicKey publicKey) {
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
this.tbsGen.setSubjectPublicKeyInfo(subjectPublicKeyInfo);
return this;
}

//
// Certificate Extensions
//

public X509CertificateBuilder setBasicContraints(boolean ca, boolean critical) throws IOException {
this.extGenerator.addExtension(Extension.basicConstraints, critical, new BasicConstraints(ca));
return this;
}

public X509CertificateBuilder setAuthorityKeyIdentifier(PublicKey caPublicKey, boolean critical)
throws NoSuchAlgorithmException, IOException {

this.extGenerator.addExtension(Extension.authorityKeyIdentifier, critical,
new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caPublicKey));
return this;
}

public X509CertificateBuilder setSubjectKeyIdentifier(PublicKey publicKey, boolean critical)
throws NoSuchAlgorithmException, IOException {

this.extGenerator.addExtension(Extension.subjectKeyIdentifier, critical,
new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey));
return this;
}

public X509CertificateBuilder setAuthorityInformationAccess(String ocspUri, String caIssuersUri, boolean critical)
throws IOException {

GeneralName ocspName = new GeneralName(GeneralName.uniformResourceIdentifier, ocspUri);
GeneralName caIssuersName = new GeneralName(GeneralName.uniformResourceIdentifier, caIssuersUri);

AccessDescription ocsp = new AccessDescription(AccessDescription.id_ad_ocsp, ocspName);
AccessDescription caIssuers = new AccessDescription(AccessDescription.id_ad_caIssuers, caIssuersName);

AuthorityInformationAccess authorityInformationAccess = new AuthorityInformationAccess(
new AccessDescription[] { ocsp, caIssuers });
this.extGenerator.addExtension(Extension.authorityInfoAccess, critical, authorityInformationAccess);
return this;
}

public X509CertificateBuilder setCRLDistributionPoints(String cdpUri, boolean critical) throws IOException {
GeneralNames generalNames = new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, cdpUri));
DistributionPoint[] distPoints = new DistributionPoint[] {
new DistributionPoint(new DistributionPointName(generalNames), null, null) };
this.extGenerator.addExtension(Extension.cRLDistributionPoints, critical, new CRLDistPoint(distPoints));
return this;
}

public X509CertificateBuilder setCertificatePolicies(String[] certificatePolicyIds, boolean critical)
throws IOException {

PolicyInformation[] policyInfos = new PolicyInformation[certificatePolicyIds.length];
for (int i = 0; i < certificatePolicyIds.length; ++i) {
policyInfos[i] = new PolicyInformation(new ASN1ObjectIdentifier(certificatePolicyIds[i]));
}
this.extGenerator.addExtension(Extension.certificatePolicies, critical, new CertificatePolicies(policyInfos));
return this;
}

public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, boolean critical) throws IOException {
this.extGenerator.addExtension(Extension.keyUsage, critical,
new org.bouncycastle.asn1.x509.KeyUsage(keyUsage1.getValue()));
return this;
}

public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, KeyUsage keyUsage2, boolean critical)
throws IOException {

this.extGenerator.addExtension(Extension.keyUsage, critical,
new org.bouncycastle.asn1.x509.KeyUsage(keyUsage1.getValue() | keyUsage2.getValue()));
return this;
}

public X509CertificateBuilder setKeyUsage(KeyUsage keyUsage1, KeyUsage keyUsage2, KeyUsage keyUsage3,
boolean critical) throws IOException {

this.extGenerator.addExtension(Extension.keyUsage, critical, new org.bouncycastle.asn1.x509.KeyUsage(
keyUsage1.getValue() | keyUsage2.getValue() | keyUsage3.getValue()));
return this;
}

public X509CertificateBuilder setExtendedKeyUsage(KeyPurposeId[] keyPurposeIds, boolean critical)
throws IOException {

this.extGenerator.addExtension(Extension.extendedKeyUsage, critical, new ExtendedKeyUsage(keyPurposeIds));
return this;
}

public X509CertificateBuilder setSubjectAlternativeNamesDNS(String[] hostnames, boolean critical)
throws IOException {

GeneralName[] generalNames = new GeneralName[hostnames.length];
for (int i = 0; i < hostnames.length; ++i) {
generalNames[i] = new GeneralName(GeneralName.dNSName, hostnames[i]);
}
this.extGenerator.addExtension(Extension.subjectAlternativeName, critical, new GeneralNames(generalNames));
return this;
}

public X509CertificateBuilder setSubjectAlternativeNamesUPN(String upn, boolean critical) throws IOException {
this.extGenerator.addExtension(Extension.subjectAlternativeName, critical, new GeneralNames(new GeneralName(
GeneralName.otherName,
new DERSequence(new ASN1Encodable[] { MSUPN_OID, new DERTaggedObject(0, new DERUTF8String(upn)) }))));
return this;
}

public java.security.cert.X509Certificate build(PrivateKey caPrivateKey, String signatureAlgorithm)
throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm)
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(caPrivateKey);

this.tbsGen.setSignature(contentSigner.getAlgorithmIdentifier());
this.tbsGen.setExtensions(this.extGenerator.generate());

TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
X509CertificateHolder X509CertificateHolder = new X509CertificateHolder(generateStructure(tbsCert,
contentSigner.getAlgorithmIdentifier(), generateSig(contentSigner, tbsCert)));

return new JcaX509CertificateConverter().getCertificate(X509CertificateHolder);
}

// ----------------------- Helper Methods -----------------------

// org.bouncycastle.asn1.x509.KeyUsage
public enum KeyUsage {

DIGITAL_SIGNATURE(org.bouncycastle.asn1.x509.KeyUsage.digitalSignature), //
NON_REPUDIATION(org.bouncycastle.asn1.x509.KeyUsage.nonRepudiation), //
KEY_ENCIPHERMENT(org.bouncycastle.asn1.x509.KeyUsage.keyEncipherment), //
DATA_ENCIPHERMENT(org.bouncycastle.asn1.x509.KeyUsage.dataEncipherment), //
KEY_AGREEMENT(org.bouncycastle.asn1.x509.KeyUsage.keyAgreement), //
KEY_CERT_SIGN(org.bouncycastle.asn1.x509.KeyUsage.keyCertSign), //
CRL_SIGN(org.bouncycastle.asn1.x509.KeyUsage.cRLSign);

private final int value;

KeyUsage(int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

protected byte[] generateSig(ContentSigner signer, ASN1Object tbsObj) throws IOException {
OutputStream sOut = signer.getOutputStream();
tbsObj.encodeTo(sOut, ASN1Encoding.DER);
sOut.close();
return signer.getSignature();
}

protected Certificate generateStructure(TBSCertificate tbsCert, AlgorithmIdentifier sigAlgId, byte[] signature) {
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add(sigAlgId);
v.add(new DERBitString(signature));
return Certificate.getInstance(new DERSequence(v));
}

// ----------------------- Get and Set Methods -----------------------

}

And certificate profile builder.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.operator.OperatorCreationException;

import se.magnuskkarlsson.example.bouncycastle.X509CertificateBuilder.KeyUsage;

public class X509CertificateProfile {

// ----------------------- Logic Methods -----------------------

public X509Certificate createCA(KeyPair caKeyPair, X500Name subjectDN, String cdpUri)
throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

return new X509CertificateBuilder() //
// mandatory fields
.setSerialNumber(getSerialNumber()) //
.setIssuerDN(subjectDN) //
.setValidity(10) //
.setSubjectDN(subjectDN) //
.setSubjectPublicKeyInfo(caKeyPair.getPublic()) //
// certificate extensions
.setBasicContraints(true, true) //
.setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
.setSubjectKeyIdentifier(caKeyPair.getPublic(), false) //
.setCRLDistributionPoints(cdpUri, false) //
.setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.KEY_CERT_SIGN, KeyUsage.CRL_SIGN, true) //
.build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
}

public X509Certificate createServer(KeyPair caKeyPair, KeyPair keyPair, X500Name issuerDN, X500Name subjectDN,
String ocspUri, String caIssuersUri, String cdpUri, String[] hostnames)
throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

return new X509CertificateBuilder() //
// mandatory fields
.setSerialNumber(getSerialNumber()) //
.setIssuerDN(issuerDN) //
.setValidity(1) //
.setSubjectDN(subjectDN) //
.setSubjectPublicKeyInfo(keyPair.getPublic()) //
// certificate extensions
.setBasicContraints(false, true) //
.setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
.setSubjectKeyIdentifier(keyPair.getPublic(), false) //
.setAuthorityInformationAccess(ocspUri, caIssuersUri, false) //
.setCRLDistributionPoints(cdpUri, false) //
.setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.KEY_ENCIPHERMENT, false) //
.setExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_serverAuth }, false)
.setSubjectAlternativeNamesDNS(hostnames, false) //
.build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
}

public X509Certificate createClient(KeyPair caKeyPair, KeyPair keyPair, X500Name issuerDN, X500Name subjectDN,
String ocspUri, String caIssuersUri, String cdpUri, String upn)
throws OperatorCreationException, CertificateException, NoSuchAlgorithmException, IOException {

return new X509CertificateBuilder() //
// mandatory fields
.setSerialNumber(getSerialNumber()) //
.setIssuerDN(issuerDN) //
.setValidity(1) //
.setSubjectDN(subjectDN) //
.setSubjectPublicKeyInfo(keyPair.getPublic()) //
// certificate extensions
.setBasicContraints(false, true) //
.setAuthorityKeyIdentifier(caKeyPair.getPublic(), false) //
.setSubjectKeyIdentifier(keyPair.getPublic(), false) //
.setAuthorityInformationAccess(ocspUri, caIssuersUri, false) //
.setCRLDistributionPoints(cdpUri, false) //
.setKeyUsage(KeyUsage.DIGITAL_SIGNATURE, KeyUsage.NON_REPUDIATION, KeyUsage.KEY_ENCIPHERMENT, true) //
.setExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth }, false)
.setSubjectAlternativeNamesUPN(upn, false) //
.build(caKeyPair.getPrivate(), CAKeyStore.SHA256_RSA_SIGNATURE);
}

// ----------------------- Helper Methods -----------------------

protected BigInteger getSerialNumber() {
// RFC 5280 and X.690

// Effective September 30, 2016, CAs SHALL generate non-sequential Certificate serial numbers greater than zero
// (0) containing at least 64 bits of output from a CSPRNG.
return BigInteger.valueOf(System.currentTimeMillis());
}

// ----------------------- Get and Set Methods -----------------------

}

And unit test.


package se.magnuskkarlsson.example.bouncycastle;

import java.io.File;
import java.security.KeyPair;
import java.security.Security;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class X509CertificateProfileTest {

private static KeyPair caKeyPair;
private static X500Name caSubjectDN;
private String ocspUri = "http://ocsp.mkk.se/";
private String caIssuersUri = "http://pki.mkk.se/ca.crt";
private String cdpUri = "http://crl.mkk.se/ca.crl";

@BeforeClass
public static void oneTimeSetUp() throws Exception {
Security.addProvider(new BouncyCastleProvider());
caKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 4096);
caSubjectDN = new X500NameBuilder() //
.addRDN(BCStyle.CN, "FOO CA") //
.addRDN(BCStyle.O, "MKK") //
.addRDN(BCStyle.C, "SE") //
.build();
}

@Before
public void setUp() throws Exception {
}

@After
public void tearDown() {
}

@AfterClass
public static void oneTimeTearDown() throws Exception {
}

// ----------------------- Test Methods -----------------------

@Test
public void createCA() throws Exception {
X509Certificate caCert = new X509CertificateProfile().createCA(caKeyPair, caSubjectDN, cdpUri);

System.out.println(caCert);
EncryptionUtils.writePEM(caCert, File.createTempFile("caCert-", ".crt.pem"));
}

@Test
public void createServer() throws Exception {
KeyPair serverKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 2048);
X500Name serverSubjectDN = new X500NameBuilder() //
.addRDN(BCStyle.CN, "FQDN") //
.addRDN(BCStyle.OU, "mywebapp") //
.addRDN(BCStyle.O, "MKK") //
.addRDN(BCStyle.C, "SE") //
.build();
String[] hostnames = new String[] { "localhost", "127.0.0.1" };

X509Certificate serverCert = new X509CertificateProfile().createServer(caKeyPair, serverKeyPair, caSubjectDN,
serverSubjectDN, ocspUri, caIssuersUri, cdpUri, hostnames);

System.out.println(serverCert);
EncryptionUtils.writePEM(serverCert, File.createTempFile("serverCert-", ".crt.pem"));
}

@Test
public void createClient() throws Exception {
X509Certificate caCert = new X509CertificateProfile().createCA(caKeyPair, caSubjectDN, cdpUri);

KeyPair clientKeyPair = new CAKeyStore(new Configurations()).createKeyPair(CAKeyStore.RSA_ALGORITHM, 2048);
X500Name clientSubjectDN = new X500NameBuilder() //
.addRDN(BCStyle.CN, "Magnus K Karlsson") //
.addRDN(BCStyle.OU, "1000") //
.addRDN(BCStyle.O, "MKK") //
.addRDN(BCStyle.C, "SE") //
.build();
String upn = "1000@mkk.se";

X509Certificate clientCert = new X509CertificateProfile().createClient(caKeyPair, clientKeyPair, caSubjectDN,
clientSubjectDN, ocspUri, caIssuersUri, cdpUri, upn);

System.out.println(clientCert);
EncryptionUtils.writePEM(clientCert, File.createTempFile("clientCert-", ".cert.pem"));
System.out.println(EncryptionUtils.getMSUPN(clientCert));
EncryptionUtils.writeKeyStore("PKCS12", clientKeyPair.getPrivate(), "changeit",
new X509Certificate[] { clientCert, caCert }, File.createTempFile("clientCert-", ".p12"));
}

}

And when run.


[
[
Version: V3
Subject: C=SE, O=MKK, OU=1000, CN=Magnus K Karlsson
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

Key: Sun RSA public key, 2048 bits
params: null
modulus: 25571568211886603124840374772893412632803008320276441343266420556001859527212495329059106511242070860135631150070936589994653782417968024014212169649126808218158560179639047989539457693799118359900429037050920421546627123472786524557783697159392478858239658746621633838155562268034256430543588459559201972100435495705680421356703692111342204230448132868538272476016901917159213800485636336183819543618065791989738031811366034365221624184676389882604646322575407826629234052470133086130458566129601941794090632783578168688778972919128563980379914647410944834699287955276441401709227130144873341655798718948150387040663
public exponent: 65537
Validity: [From: Mon Mar 02 20:35:28 CET 2020,
To: Tue Mar 02 20:35:28 CET 2021]
Issuer: C=SE, O=MKK, CN=FOO CA
SerialNumber: [ 01709cbf 0140]

Certificate Extensions: 8
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: ocsp
accessLocation: URIName: http://ocsp.mkk.se/
,
accessMethod: caIssuers
accessLocation: URIName: http://pki.mkk.se/ca.crt
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73 9D D0 60 C4 42 A3 80 95 .[..N..s..`.B...
0010: 37 7B 9A 1B 7...
]
]

[3]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]

[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.mkk.se/ca.crl]
]]

[5]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
clientAuth
]

[6]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Non_repudiation
Key_Encipherment
]

[7]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
Other-Name: Unrecognized ObjectIdentifier: 1.3.6.1.4.1.311.20.2.3
]

[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 63 31 5B A3 22 8C C0 4B DF 2D 7B 39 4C 43 D2 DB c1[."..K.-.9LC..
0010: 11 96 37 46 ..7F
]
]

]
Algorithm: [SHA256withRSA]
Signature:
0000: 85 9B 22 22 44 4E E0 59 44 31 12 53 39 D5 A4 78 ..""DN.YD1.S9..x
0010: DA 39 80 BC 53 47 94 D1 B3 B6 E3 2B 8F D4 39 92 .9..SG.....+..9.
0020: 7B 63 CE FA 48 53 33 BF B6 4B E7 83 90 47 AA 2D .c..HS3..K...G.-
0030: 32 B6 02 9F A9 1B EE 27 02 7C 68 B2 9F 50 D4 D2 2......'..h..P..
0040: 55 2C A4 B6 1C 09 F1 BF AE 0A A6 39 60 DE 93 CA U,.........9`...
0050: 74 32 54 8F 74 E0 5B F8 0D 32 FE 6E 02 6B 88 9D t2T.t.[..2.n.k..
0060: 2F D7 0C 9D A7 DE 20 5B 10 0A 08 61 1A 76 B0 35 /..... [...a.v.5
0070: 80 E3 AF C6 4C A9 06 E0 38 2F 9F D8 48 E8 BE DC ....L...8/..H...
0080: 89 C0 DF 64 E2 F3 72 3C BC 51 A8 D9 F2 1E 18 4A ...d..r<.Q.....J
0090: 1B 52 1D E1 2E D7 EA 23 37 4C CA 4C A6 8A E6 85 .R.....#7L.L....
00A0: 60 7D 29 63 4F A0 90 37 29 EE CF 0E 0E 05 0E 85 `.)cO..7).......
00B0: 93 47 63 BC 7C CF CE 58 58 71 72 56 76 45 63 0A .Gc....XXqrVvEc.
00C0: D6 33 BD EF 53 9A 8C F1 19 EE E7 AE 8E 8E 76 A0 .3..S.........v.
00D0: 37 7B BE 45 B5 C8 7B 72 FD 29 8B 80 0B 74 5E 24 7..E...r.)...t^$
00E0: 71 66 3D C9 39 A0 6B 24 B2 91 09 57 9C B7 2D 2E qf=.9.k$...W..-.
00F0: 82 B8 D7 CA 7A 71 CF 05 2C 97 89 76 DC 3D 2A B8 ....zq..,..v.=*.
0100: 10 A0 8C 27 8D 49 2A 23 C9 8E FB D1 2B 55 00 6D ...'.I*#....+U.m
0110: 76 CE 2D 86 8A E1 4D B4 1C 9E 8C 47 15 BC 7F DF v.-...M....G....
0120: 20 23 D1 09 27 A3 DB 9B 7F AC D9 AE D7 72 D3 A3 #..'........r..
0130: E0 20 63 91 1A 49 A6 77 3E B2 EE F0 B1 57 8D 77 . c..I.w>....W.w
0140: 62 11 3C E2 17 28 6F CB BE 44 14 A3 06 23 89 74 b.<..(o..D...#.t
0150: DE 05 75 DC CB D7 2A 86 3D 9A FA 29 94 00 82 09 ..u...*.=..)....
0160: 3D B1 DE A9 12 F1 48 30 F2 5C 52 10 0D 81 CA 5A =.....H0.\R....Z
0170: 69 8A 9B F5 3B 7A F4 CB 8A D7 51 AE 5A CD A1 51 i...;z....Q.Z..Q
0180: FA F8 66 AF FC 02 68 2D E9 CC D7 AF C1 FA 21 84 ..f...h-......!.
0190: 0C 1B 7A 0F DE B9 3D 9A 8A 1A 61 BC 46 01 3A FD ..z...=...a.F.:.
01A0: 62 E3 79 35 07 66 64 A7 17 83 5E 82 E9 93 A2 FA b.y5.fd...^.....
01B0: 6F D7 83 38 99 5F 44 69 6C AA F3 32 E4 B4 48 59 o..8._Dil..2..HY
01C0: 50 EC 64 14 72 51 9A E9 95 BC 4E CE EA 98 B3 BD P.d.rQ....N.....
01D0: 7C F4 BD D2 60 D3 07 7C 71 26 24 55 94 E5 AA D5 ....`...q&$U....
01E0: 44 A1 8D AC 30 AE 47 CA FF 96 FD CA 9E 03 25 EC D...0.G.......%.
01F0: 55 5B 97 5B 27 24 A3 23 8F 0D CD 9A DC 52 29 BA U[.['$.#.....R).

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/clientCert-9146518211353882041.cert.pem
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils getMSUPN
INFO: Read X509 SAN [[0, [1.3.6.1.4.1.311.20.2.3, [0]1000@mkk.se]]]
1000@mkk.se
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writeKeyStore
INFO: Wrote /tmp/clientCert-14620146327205577598.p12
[
[
Version: V3
Subject: C=SE, O=MKK, OU=mywebapp, CN=FQDN
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

Key: Sun RSA public key, 2048 bits
params: null
modulus: 23472554064383360225540326318244541407904103528288156342671235877676704006249990542080185400202587647452428079635384512450814661982177331214162132359638484764547017758245274776079283522876250682767182225000730754889702275736425322221042334223219623764657811814147865593555449798942802445890347917633973214547390327111222760190458870434688746315828193389701570278446761804026480172159526376218012304574882822703261195947214666386714673839238432567588108434506291951836819612851494156727230958145708637864415669786989760083242288799613934351495483902217961576331883073677917645326766725734237025938297058790630425487583
public exponent: 65537
Validity: [From: Mon Mar 02 20:35:28 CET 2020,
To: Tue Mar 02 20:35:28 CET 2021]
Issuer: C=SE, O=MKK, CN=FOO CA
SerialNumber: [ 01709cbf 02ae]

Certificate Extensions: 8
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: ocsp
accessLocation: URIName: http://ocsp.mkk.se/
,
accessMethod: caIssuers
accessLocation: URIName: http://pki.mkk.se/ca.crt
]
]

[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73 9D D0 60 C4 42 A3 80 95 .[..N..s..`.B...
0010: 37 7B 9A 1B 7...
]
]

[3]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]

[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.mkk.se/ca.crl]
]]

[5]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
]

[6]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
DigitalSignature
Key_Encipherment
]

[7]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: localhost
DNSName: 127.0.0.1
]

[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: C4 54 8A E7 43 33 30 53 AD B5 7F 07 81 57 17 3F .T..C30S.....W.?
0010: 74 B2 6A 97 t.j.
]
]

]
Algorithm: [SHA256withRSA]
Signature:
0000: 5D C5 A5 AC 37 CA F7 AE A8 34 80 C7 17 DF 27 01 ]...7....4....'.
0010: 12 C1 CB 8A 8D 85 77 98 01 EB FD 44 21 63 1F 98 ......w....D!c..
0020: 51 69 67 E8 96 16 AA CF 9C 2A 6A 10 8B 3B F4 60 Qig......*j..;.`
0030: 8D 5C 66 46 6C E4 C4 A8 A0 60 A6 3E 43 35 40 FC .\fFl....`.>C5@.
0040: 77 5C 9A DA 13 D8 F9 F1 63 35 FD 0F 4B 6C A4 11 w\......c5..Kl..
0050: 5D 67 CF DA 73 9B E0 A0 35 05 6E 37 7A D9 E2 AF ]g..s...5.n7z...
0060: 10 80 A1 CA F5 5F D4 01 A7 6B 76 92 99 2F 74 25 ....._...kv../t%
0070: A6 27 D2 67 05 07 D9 E6 27 58 E6 90 D1 C0 2D B1 .'.g....'X....-.
0080: 7A 1B F9 5B 91 6E BE DD AB A8 AA EB B4 BB AE 96 z..[.n..........
0090: 9E 26 A8 CB 31 CE 4B 02 BE EA D4 6A AC B5 E5 FA .&..1.K....j....
00A0: 43 76 E4 8E C9 16 BF 55 34 E6 D0 A8 FA 1C 6D 48 Cv.....U4.....mH
00B0: C9 54 65 37 84 89 F6 13 C4 FD 0C 62 41 FF 57 5B .Te7.......bA.W[
00C0: 88 28 35 AF 83 1C D1 A3 8C A4 1F 7F CD E0 F4 F9 .(5.............
00D0: DA 64 C2 C3 51 D7 C5 56 2C 3D 6C A3 C0 B1 40 1B .d..Q..V,=l...@.
00E0: 2E 42 B5 6F FF 86 2F DB F2 1F E6 E0 24 A1 CD 7C .B.o../.....$...
00F0: A6 94 20 95 B8 95 74 05 0B 0E CE 08 43 2E CF FA .. ...t.....C...
0100: 43 EE 30 3B 40 2C 3E 10 4F BD B2 BC 48 55 07 23 C.0;@,>.O...HU.#
0110: 2B 06 FB F0 E5 76 A2 15 1D E1 8A 33 E6 76 A2 30 +....v.....3.v.0
0120: 6C 07 4C 2A B4 57 C3 62 51 DE 58 1A 5D 82 11 84 l.L*.W.bQ.X.]...
0130: 3F AF EE 17 EC 8B C9 8F EA F8 6F E4 C1 6A 1F C8 ?.........o..j..
0140: 41 2A 15 62 4C DC 99 37 49 9E 58 1D 95 E1 A6 2E A*.bL..7I.X.....
0150: AC F4 D3 4F 7F 44 87 B8 18 CD 34 D0 C5 85 9B A6 ...O.D....4.....
0160: C1 46 CD 68 80 84 BE F0 1D F0 E2 B2 2F 0E D3 A6 .F.h......../...
0170: DB 68 89 FD 4A F8 A5 35 AA CB 6A CC FA 45 9E 20 .h..J..5..j..E.
0180: 9D AA 1D 04 2F 14 8D D0 A4 2B 78 09 9A 23 DA 44 ..../....+x..#.D
0190: 65 76 54 CF D3 7B 7F 37 78 46 18 45 60 98 0D 63 evT....7xF.E`..c
01A0: 2A 7D F8 0D A6 0C 0B 1A 81 61 B8 2B 1F A3 92 E9 *........a.+....
01B0: F2 9C 5B 26 E9 81 50 6F D9 79 8B 03 54 64 6C EB ..[&..Po.y..Tdl.
01C0: AA 4A A1 B6 B3 6F 82 C8 20 9D D1 33 D5 D3 87 DA .J...o.. ..3....
01D0: 5A 3E 93 2A 22 FA BE 0A A8 1F B6 A4 5C AA E0 73 Z>.*".......\..s
01E0: 17 76 73 33 61 B0 7E ED 09 5E FD DB 4F B7 5A B4 .vs3a....^..O.Z.
01F0: 76 21 1B FA 43 F0 52 AE 78 DC 3B 09 06 66 45 B2 v!..C.R.x.;..fE.

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/serverCert-12014046357869706442.crt.pem
[
[
Version: V3
Subject: C=SE, O=MKK, CN=FOO CA
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

Key: Sun RSA public key, 4096 bits
params: null
modulus: 618097494562805236224635134817934912453172250162709722041733040687097334018651185958049454716082071938067246709420916424794899282956550425042006414596550620844500042869814998708415847406596390541333435551567170239109985394967160893875673187989640416587377196814478200867973805718141593244866119267189530684758333327813430426324393329942084968006256517216438373301377640102657162289647735616023682850661875444729876016663906609090034297679982852109216895370934293109110480164998867564217281544316832079056015576106175918287779836237538131308742105170670592053973122534872165219807886684564067083803402486128679568799840125501397600441124322949161232699891631680388114085515962034617420771247637630876469717153740862760325747621475058600558255078199328046206047780514609430807802825141363344880107809474319017977033492293123813011848757820259401796458615662171411629964165721128392643210117405003344910890867964280963490337780332547309122266515542815534797820516503892594199239179401978336582637760762233031975748737882775045900183794816021065220038962704464619646627020923143975929999810020514328195611426571022736233127780297192743641966846131645647190538362059522204380559481497214913394154203383211767929658852311603605904982991909
public exponent: 65537
Validity: [From: Mon Mar 02 20:35:28 CET 2020,
To: Sat Mar 02 20:35:28 CET 2030]
Issuer: C=SE, O=MKK, CN=FOO CA
SerialNumber: [ 01709cbf 02c1]

Certificate Extensions: 5
[1]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73 9D D0 60 C4 42 A3 80 95 .[..N..s..`.B...
0010: 37 7B 9A 1B 7...
]
]

[2]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]

[3]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://crl.mkk.se/ca.crl]
]]

[4]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_CertSign
Crl_Sign
]

[5]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 13 5B F4 D2 4E 05 F0 73 9D D0 60 C4 42 A3 80 95 .[..N..s..`.B...
0010: 37 7B 9A 1B 7...
]
]

]
Algorithm: [SHA256withRSA]
Signature:
0000: 6B 5A 8D 8E 93 F0 97 BC 6C 62 DD 1A 65 22 75 10 kZ......lb..e"u.
0010: D1 E3 95 AF BA B8 C1 93 45 C9 44 0A EB 36 93 A8 ........E.D..6..
0020: FD 3C 6F 62 28 FF 59 68 14 8E 7E 45 BB 8E C9 68 .<ob(.Yh...E...h
0030: 0C F3 ED 7F 6D E1 9B FC D1 22 58 06 FB 6A EF ED ....m...."X..j..
0040: DC 34 E9 BA CD 7C 69 A9 73 FB F7 C6 7C FD 7A 43 .4....i.s.....zC
0050: 86 68 8A B9 10 F7 36 BC 1E E5 98 99 C4 1A 9D 43 .h....6........C
0060: 31 00 3B 22 38 BB 7E 96 1C 32 E6 8C 67 F4 66 3A 1.;"8....2..g.f:
0070: 37 D9 58 24 18 74 30 40 9C 4B 0C 23 BE 11 4E B1 7.X$.t0@.K.#..N.
0080: 11 4F AD 1D F2 C0 94 1D B3 B1 A5 CB FE C9 86 5B .O.............[
0090: 39 80 C9 B1 86 5A 0F 76 C9 4A 54 04 CC 0D 3B E0 9....Z.v.JT...;.
00A0: 94 0F 51 86 8F D8 5E FE 81 21 20 B7 38 9E 91 C4 ..Q...^..! .8...
00B0: FE B3 78 67 80 BF 0E 95 4F C7 E8 48 59 DB CA 43 ..xg....O..HY..C
00C0: E7 69 48 52 C1 78 DA 89 E1 2E 98 63 5E 5A B5 E6 .iHR.x.....c^Z..
00D0: 7B C5 DB D6 B9 35 4E 8A 52 5E 6F 22 EA AD CE 8E .....5N.R^o"....
00E0: 8C CF BF D3 41 0A 46 35 66 8A C1 E6 53 BE 1C 00 ....A.F5f...S...
00F0: EF 86 FE D7 C6 D9 62 EF 11 AC 44 49 6B 06 4E EC ......b...DIk.N.
0100: 59 1F 5B 03 D1 CC 63 2F 05 49 1A B4 B0 66 01 55 Y.[...c/.I...f.U
0110: 93 FF 89 CB F1 DA 1E E5 3A 21 E1 81 A5 9D E1 A5 ........:!......
0120: A5 5F 3D AF CF 7C 88 B6 F9 03 EF C8 23 A5 04 3F ._=.........#..?
0130: F6 CE EE 3A AB A0 A2 7F 0D 33 69 18 E3 A2 22 D8 ...:.....3i...".
0140: 7A 2E 09 1A B2 E5 7A 7C EA 15 08 92 3D D5 D8 8A z.....z.....=...
0150: 83 AE 6F CC 4D 30 73 CB 30 A1 0D D1 CC 47 B8 16 ..o.M0s.0....G..
0160: E3 2A 4B 06 32 79 99 4C 1E DD 92 5A 7D CD CB F3 .*K.2y.L...Z....
0170: 00 07 65 86 33 83 06 9C F9 5C 45 2C F9 F2 E7 36 ..e.3....\E,...6
0180: BB 78 8C 47 32 B6 A6 8B 6F 11 91 73 CF 92 EF B7 .x.G2...o..s....
0190: 60 22 12 48 2F 01 1F 99 81 6C C0 0D 9B 6F 76 00 `".H/....l...ov.
01A0: D3 CD 1D F9 89 F8 F9 F0 83 7D 34 3E F2 6C 08 41 ..........4>.l.A
01B0: F9 EA 1B 8D BC CF 7A 41 7B A0 89 F4 55 8E 09 94 ......zA....U...
01C0: AC FC 50 4B 99 E6 BA 21 04 CF 33 BD B5 2F B7 B0 ..PK...!..3../..
01D0: 06 38 59 89 8C 04 E8 4D C0 A4 D1 13 DD 47 25 4A .8Y....M.....G%J
01E0: 02 CE AC CA BE 75 C3 4A 30 A7 9C 84 0A 7E 1D 59 .....u.J0......Y
01F0: BA 2A AA 6C 58 C7 0C 7B BA 60 60 B3 77 E2 72 AE .*.lX....``.w.r.

]
Mar 02, 2020 8:35:28 PM se.magnuskkarlsson.example.bouncycastle.EncryptionUtils writePEM
INFO: Wrote /tmp/caCert-12617038054227389688.crt.pem

How to Upgrade Fedora 30 to Fedora 31

$
0
0

Prerequisite

>$ cat /etc/fedora-release 
Fedora release 30 (Thirty)

Update software and back up your system.

>$ sudo dnf upgrade --refresh

Install the DNF plugin.

>$ sudo dnf install dnf-plugin-system-upgrade

Start the update with DNF.

>$ sudo dnf system-upgrade download --releasever=31

Reboot and upgrade.

>$ sudo dnf system-upgrade reboot

How to Change to Normal Ctrl+Tab Switching Tabs in Firefox

$
0
0

Open Edit -> Preferences -> General | Tabs and uncheck "Ctrl+Tab cycles through tabs in recently used order".

Fedora 31 don't Group Application when Alt + Tab

How To Install MySQL Community Edition 8.0 on Fedora 32/31/30/29

$
0
0

Follow the guide https://computingforgeeks.com/how-to-install-mysql-8-on-fedora/

>$ sudo dnf install mysql-community-server mysql-community-client

$ sudo systemctl start mysqld

$ sudo grep 'A temporary password' /var/log/mysqld.log |tail -1
2020-11-16T19:23:52.286885Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: sggCqq50Qh/Y

There is a gotcha when installing the MySQL Community Edition and that is root password is generated randomly. This is good for production, but for development it is more easy to have a simple password.

To set a trivial root password you first need to disable password policy.

>$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.22
...

mysql> UNINSTALL COMPONENT 'file://component_validate_password';
Query OK, 0 rows affected (0.00 sec)

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'root';
Query OK, 0 rows affected (0.02 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql> exit
Bye
Viewing all 526 articles
Browse latest View live