Dependency Hell

It is not a secret even if we try to hide from it.

The dependencies in writing any application today is a nightmare and a lot of work to maintain straight.

Google has a tool to look at some open-source project and as much as it is not the first of such tool, I like the graph mode available.

https://deps.dev

I was trying to find something interesting to look at but most java projects I looked at had simple graphs. I found this one that makes the tool visual shine a bit:

https://deps.dev/maven/com.android.tools.build%3Agradle/2.3.0/dependencies/graph

Interesting tool.

Keycloak Identity Provider ID

That took a couple of hours to figure out so let’s share some notes.

I have code that creates the required Keycloak Realms and configures a few items in each of them.

One of those configuration is to create the Identity Provider so that we can link users to another realm. Internal SSO if you will.

I tested this with Keycloak 11.0.3.

I did not understand that the Identity Provider ID needed to be one of the specific values since it is only a string that you pass to it. Sometimes I wish they could use an enum to help users make sense of it quickly.

After getting errors that it was a required fields and trying a few values that did not make sense to Keycloak.

10:39:07.587 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [password]"}"

10:41:50.814 [main] DEBUG org.apache.http.wire - http-outgoing-0 << "{"errorMessage":"Invalid identity provider id [EmailAuthProviderID]"}"

I tried keycloak-oidc and it worked. So the value needs to be one of these:

  • saml
  • oidc
  • keycloak-oidc

You could also use one of the social identity provider.

I also understood to take the config from the endpoint:

http://192.168.1.50:8080/auth/realms/Customer/.well-known/openid-configuration

Sample code:

IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
identityProviderRepresentation.setDisplayName(IDP);
identityProviderRepresentation.setProviderId("keycloak-oidc");
identityProviderRepresentation.setAlias(IDP);
Map<String, String> config = new HashMap<>();
config.put("issuer", "http://192.168.1.50:8080/auth/realms/Customer");
config.put("authorization_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/auth");
config.put("token_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/token");
config.put("introspection_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/token/introspect");
config.put("userinfo_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/userinfo");
config.put("end_session_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/logout");
config.put("jwks_uri", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/certs");
config.put("check_session_iframe", "http://192.168.1.50:8080/auth/realms/Customer/protocol/openid-connect/login-status-iframe.html");
config.put("grant_types_supported", "[\"authorization_code\",\"implicit\",\"refresh_token\",\"password\",\"client_credentials\"]");
config.put("response_types_supported", "[\"code\",\"none\",\"id_token\",\"token\",\"id_token token\",\"code id_token\",\"code token\",\"code id_token token\"]");
config.put("subject_types_supported", "[\"public\",\"pairwise\"]");
config.put("id_token_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("id_token_encryption_alg_values_supported", "[\"RSA-OAEP\",\"RSA1_5\"]");
config.put("id_token_encryption_enc_values_supported", "[\"A256GCM\",\"A192GCM\",\"A128GCM\",\"A128CBC-HS256\",\"A192CBC-HS384\",\"A256CBC-HS512\"]");
config.put("userinfo_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("request_object_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\",\"none\"]");
config.put("response_modes_supported", "[\"query\",\"fragment\",\"form_post\"]");
config.put("registration_endpoint", "http://192.168.1.50:8080/auth/realms/Customer/clients-registrations/openid-connect");
config.put("token_endpoint_auth_methods_supported", "[\"private_key_jwt\",\"client_secret_basic\",\"client_secret_post\",\"tls_client_auth\",\"client_secret_jwt\"]");
config.put("token_endpoint_auth_signing_alg_values_supported", "[\"PS384\",\"ES384\",\"RS384\",\"HS256\",\"HS512\",\"ES256\",\"RS256\",\"HS384\",\"ES512\",\"PS256\",\"PS512\",\"RS512\"]");
config.put("claims_supported", "[\"aud\",\"sub\",\"iss\",\"auth_time\",\"name\",\"given_name\",\"family_name\",\"preferred_username\",\"email\",\"acr\"]");
config.put("claim_types_supported", "[\"normal\"]");
config.put("claims_parameter_supported", "false");
config.put("scopes_supported", "[\"openid\",\"offline_access\", \"profile\",\"email\",\"address\",\"phone\",\"roles\",\"web-origins\",\"microprofile-jwt\"]");
config.put("request_parameter_supported", "true");
config.put("request_uri_parameter_supported", "true");
config.put("code_challenge_methods_supported", "[\"plain\",\"S256\"]");
config.put("tls_client_certificate_bound_access_tokens", "true");
identityProviderRepresentation.setConfig(config);

Finally, I have creation of the Identity Provider in my realm and I can link users to it.

Now from Zeit

I have heard of serverless from so many vendors by now that it feels more about marketing than anything else. I have a bad gut reaction when I feel that there is more marketing than substance about any technology.

I decided to look at Now from Zeit just out of curiosity and I think that I should look at it a bit more since it looks quite easy.

On the Zeit site, you can see the free offering that they have and it allows you to get your feet wet and be more curious about what you can do.

The Now CLI also looks like a very simple way to perform everything you need.

I also like the immutability approach that they have that allows you to move quickly from one deployed version to another.

It is definitely worth more time to see what I could do with this platform.

Apache Commons Configuration and Map

Until today, the Apache Commons Configuration was a very helpful tool as a quick configuration utility in many projects. For loading simple configuration item it is fine.

I was trying to find a way to store and read a Map to contain some configuration and there is was no easy way that I could find. I came up with a Krusty solution for now but I am hoping that I can find something more elegant.

GitHub Repo with example code.

Jackson and mapping fields

I was trying to use the useragentstring.com api to query and map browsers to my custom object and I did not want to name my fields with agent_type, agent_name and agent_version.

Simple solution that I found on this page was to annotate my properties in the class with:

@JsonProperty(“agent_type”)
@JsonProperty(“agent_name”)
@JsonProperty(“agent_version”)

The mapping is happening automatically.

Very simple.

Using log4j for email alerts in an application

I want to explore how using log4j for email alerts in an application is feasible but how well it works in a real application.

The idea came from the fact that a team I work with change the rules for alerts on a regular basis based on the work and the situations they are caught in. It is clear that we have to stop changing the code to accommodate the new rules they give us.

Log4j is a possibility and I found this blog post that talks about it:

http://www.srccodes.com/p/article/18/send-logs-by-email-notification-using-apache-log4j-smtpappender

Impact of the scope on the maven assembly plugin

For a Spark project I needed to bundle some dependencies and I found a few Stackoverflow answers that explained to add this section to your pom.xml:

<plugin>
	<artifactId>maven-assembly-plugin</artifactId>
	<executions>
		<execution>
			<phase>package</phase>
			<goals>
				<goal>single</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<descriptorRefs>
			<descriptorRef>jar-with-dependencies</descriptorRef>
		</descriptorRefs>
	</configuration>
</plugin>

But once I packaged my application I ended up with a huge jar file. It contained everything the application needed.

My mistake was that the pom.xml did not contain the proper scope for each dependency and because of that they were all getting bundled into the jar.

Specified that a few were provided (provided) and it reduced the jar size considerably.

How a small missing piece can change other behaviours drastically.

Git error on a new repository

I was puzzled by a Git error I saw today.

I simple create a git repo on the “server”:

mkdir /git/newRepo

git init /git/newRepo

 

Then on my workstation I cloned it and added a file:

git clone ssh://server/git/newRepo

cd newRepo

vi test

git add test

git commit -m “testing”

git push

 

and I get this error:

No refs in common and none specified; doing nothing.
Perhaps you should specify a branch such as ‘master’.
fatal: The remote end hung up unexpectedly
error: failed to push some refs to ‘ssh://server/git/newRepo’

 

From reading a StackOverFlow answer I understood that the issue on the server side is that the new Git repository is open on the master branch by the user that created it and so it prevents a push to it because it could corrupt it. One way was to make the repo a bare one but another it to get the remote use into another branch than master.

On the server:

 

vi README

git add README

git commit -m “README”

git checkout -b test

 

and after that command I can pull and push normally.

 

git pull

git push

 

 

Reference:

http://stackoverflow.com/questions/2816369/git-push-error-remote-rejected-master-master-branch-is-currently-checked

Random Password Generator in Java

I needed a random password generator done in Java and while reading a few articles here and there I did not find the solution I was looking for. Piecing a few of them I came up with some code.

One of the requirement that made this a bit more complicated is that I needed to have a special character in the password but from a limited list of possible special characters.
I also needed to make sure that it respected some basic complexity rules.

It has a dependency on the commons-lang 3 library from Apache but since I already had it in my project it was easy to accommodate.

Maven dependency:

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.3.1</version>
</dependency>

Java code:

package com.halogensoftware.hosting.example;

import org.apache.commons.lang3.RandomStringUtils;

public class Random {

	public static void main(String args[]){
		String pwd = "";
		for ( int i = 0; i < 1000; i++ ) {
			do {
				pwd = RandomStringUtils.random(12, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890%#^*:");
			} while (!valid(pwd));
			System.out.println(i + ".valid pwd: " + pwd);
		}
	}

	private static boolean valid(String pwd){
		return (pwd.matches(".*([0-9]).*") && pwd.matches(".*([a-z]).*") && pwd.matches(".*([A-Z]).*") && pwd.matches(".*([%#^*:]).*"));
	}
}