Category Archives: Programming

Keycloak OAuth endpoints for Postman/HTTP Clients

When testing REST services secured by Keycloak you need to retrieve access tokens via Postman or similar REST client. If you want to implement your own client that has to authenticate with a token you also need to know the Keycloak OpenID endpoints in order to retrieve the access token, refresh it or to end the session (logout).

Retreiving the tokens for a public client using username and password

Public client is typically used for web applications and other client side apps.

Method: POST
URL: https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Body type: x-www-form-urlencoded
Form fields:
client_id <my-client-name>
grant_type password
username <username>
password <password>

Retreiving the tokens for a confidential client using client secret

Confidential client is typically used for secure apps on the back-end.

Method: POST
URL: https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Body type: x-www-form-urlencoded
Form fields:
client_id <my-confidential-client-name>
grant_type client_credentials
client_secret <my-client-secret>

Retreive an access token with a refresh token

The first two methods will yield you an access token which you use in the Authorization HTTP header and a refresh token which you save for later. Refresh tokens have much longer expire time as access tokens. The idea is that when the access token expires you use the refresh token to get a new access token. This request also gives you a new refresh token so you can keep the session alive until maximum refresh token expire time is reached. Refresh token expire time equals the session expire time.

Method: POST
URL: https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/token
Body type: x-www-form-urlencoded
Form fields:
client_id <my-client-name>
grant_type refresh_token
refresh_token <my-refresh-token>

Logout the session

To logout and invalidate the session, call a /logout endpoint with your refresh token. The validity of the refresh token is essentially the validity of your entire session.

Method: POST
URL: https://keycloak.example.com/auth/realms/myrealm/protocol/openid-connect/logout
Body type: x-www-form-urlencoded
Form fields:
client_id <my-client-name>
refresh_token <my-refresh-token>
Cen
GitHub
Eurobattle.net
Lagabuse.com
Bnetdocs

OJDBC7 in a Docker container? Prepare for trouble

Scenario: A JDK8 Docker container using OJDBC7 to connect to the database. Sounds simple enough, what could go wrong?

Simptoms: Connecting to the database randomly takes several minutes, fails with a weird SqlRecoverableException: no more data to read from socket or just works fine as if there is no problem.

The same Docker image also works fine on some machine but fails consistently on other.

The reason is this. Docker is not good at /dev/random. Probably even more so if you run it in a VM, since it's double isolated from actual entropy sources (my non scientific observation). For whatever reason, OJDBC defaults to /dev/random and this causes a block when connecting to the database due to high probability of /dev/random depletion.

Simple solution is to just mount /dev/urandom to /dev/random inside the Docker, in docker run command:

-v /dev/urandom:/dev/random

So.. if you ever want to use OJDBC inside Docker, remember this flag. It will save lives or at least spare you hours of useless debugging.

 

Cen
GitHub
Eurobattle.net
Lagabuse.com
Bnetdocs

JPQL: getting whole entities on a distinct column

If you want distinct entities in JPQL you would normally write something like this:

SELECT DISTINCT(l) FROM Letter l WHERE l.name=:name;

But this will do a DISTINCT on the whole Entity. This will also fail on Oracle DB if your Entity contains a CLOB. What if you really want to do a DISTINCT on a field, for example:

SELECT DISTINCT(l.id) FROM Letter l WHERE l.name=:name;

Unfortunately, this only returns an array of ID fields. If you want to retrieve the full entities and do a DISTINCT on a field the final query looks like:

SELECT ll FROM Letter ll WHERE ll.id IN (SELECT DISTINCT(l.id) FROM Letter l WHERE l.name=:name);
Cen
GitHub
Eurobattle.net
Lagabuse.com
Bnetdocs

StormLib and BNCSUtil now available from repositories

Update 2023: repos are currently unavailable

 

Finally after years and years of screwing around with building StormLib or BNCSUtil everytime you moved your ghost bots to another server is finally over. As of today, I am hosting both libraries in apt and rpm repositories. In the process I also discovered that StormLib managed to get into Debian Testing (https://packages.debian.org/source/stretch/stormlib) so let's hope it'll be included in the next stable release!

I also  pushed CPack generator code into both repositories, so you can build these packages yourself. BNCSUtil was forked and cleaned especially.

DEB based distros

  1. To /etc/apt/sources.list add:
    #apt.xpam.pl
    deb https://apt.xpam.pl/ jessie main
  2. Add GPG key:
    wget -qO - https://apt.xpam.pl/xpam.pl-pubkey.asc | sudo apt-key add -
  3. Update and install:
    sudo apt-get update
    sudo apt-get install stormlib bncsutil

RPM based distros

  1. In /etc/yum.repos.d/rpm.xpam.pl.repo add
    [rpm.xpam.pl]
    name = rpm.xpam.pl
    baseurl = https://rpm.xpam.pl
    

    or, with dnf on Fedora:

    dnf config-manager --add-repo https://rpm.xpam.pl
  2. If using dnf, make sure to import the public key:
    rpm --import https://rpm.xpam.pl/rpm-pubkey.asc
  3. Update and install:
    yum update && yum install stormlib bncsutil

    or dnf equivalent.

 

This was a nice project to spend a few weekends on but there are more plans in 2016 to clean and tidy up the bnet tools we all use and love:
-add CMake and CPack support to our own bots, link against upstream StormLib and release a cleaned up ghost code, ease the setup process via repo installs with full dependency resolution (mysql, boost, storm and bncsutil). Provide precompiled binaries for Windows.
-provide patches to some other popular ghost forks to work with upstream StormLib.
-package PvPGN?
-provide pkgng packages for FreeBSD. This will probably involve writing pkgng generator for CMake's CPack which could be an interesting side project in itself.

Cen
GitHub
Eurobattle.net
Lagabuse.com
Bnetdocs

Writing a Windows installer using Qt

Most of the time you don't want to write your own installer for distributing software. You use an off-the-shelf installation program that packages it all up for you instead.

But if you feel adventurous or need your installer to perform some very specific tasks you probably want to write your own. This post will shows you a few gotchas you might encounter along the way with Qt and WINAPI.

Qt Resource System

Qt resource system and it's .qrc files are perfect candidates for an installer. They allow you to package all the needed assets of your program into a single executable. If a .qrc file becomes too big however you might run into build errors like:

FatalError C1060:"compiler is out of heap space"

After hours of Googling for a solution it came down to this and this. Let me just say that increasing your Windows swap file and all the other solutions probably won't work. The easiest thing to do is to create another .qrc file and move some of the existing data files into it. If that one becomes too big you can simply create more of them.

This error can also appear if your project has too many header file inclusions. The .qrc files are being compiled into giant binary structs so it's the same problem in its core.

File permissions

This is an example code for copying an internal file to the filesystem:

QFile c(":\\somefile"); //internal file in .qrc
c.copy("path_in_filesystem");

But first we need to check whether a file already exists and remove it (think reinstall or install repair). This is needed because the copy() function has no "overwrite" parameter (which is stupid but that's Qt's fault):

QFile p("somepath/somefile");
if (p.exists()) {
  if (!p.remove()) {
    //could not remove file, permission denied
  }
}

This will fail because there is a small gotcha with the Qt resource system: all internal files are read-only! If you just copy an internal file to the filesystem it will keep it's read-only attribute and doing anything but reading the file will fail with Permission denied. Without knowing this simple and obvious fact you will lose hours trying to figure out what the hell is going on.

Setting write permissions after copy solves this problem, for example:

p.setPermissions(QFile::ReadOther|QFile::WriteOther);

Another gotcha with permissions is Windows UAC. Writing to Program Files needs admin permissions so your installer must be executed as administrator or request these privileges by default. Running it as a regular user will end up in a bunch of Permission denied errors.

The question then is, how to make your installer request admin privileges when executed. One way is to play with custom manifests and trying to integrate that with qmake… and probably fail on the end. Thankfully there is a simple solution by adding the following lines to qmake:

win32 {
    CONFIG += embed_manifest_exe
    QMAKE_LFLAGS_WINDOWS += /MANIFESTUAC:level=\'requireAdministrator\'
}

Make sure you enable UAC on your workstation computer so you can experience the same thing as your users. If you have it disabled you won't actually notice anything being wrong.

Registry

A proper installer should correctly register the program in the Add/Remove Programs and provide an uninstaller.

It basically has to write some registry entries. A great reference on required and optional entries can be found here. But there is a catch.. there is always a catch. The first one is that you probably can't use the QSettings class because it does not support additional CRegKey.Open() flags such as KEY_WOW64_64KEY. Your 32bit program should probably write to 64bit registry because that's what you see when you run regedit from the system. If you don't know the difference you might lose hours upon hours of trying to figure out why your registry is not changing while your WINAPI calls are working perfectly.

The gotcha is that the registry paths you need to write are different if your application is 32bit or 64bit.

For 32bit it is

Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\YourProduct

And for 64bit it is

Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\YourProduct

To determine whether we are running under WOW64 or not there is the following code lurking on the internets:

BOOL IsWow64() {
  typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
  LPFN_ISWOW64PROCESS fnIsWow64Process;
  BOOL bIsWow64 = FALSE;
  //IsWow64Process is not available on all supported versions of Windows.
  //Use GetModuleHandle to get a handle to the DLL that contains the      function
  //and GetProcAddress to get a pointer to the function if available.
  fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
  GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
  if(NULL != fnIsWow64Process) {
    if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) {
      //handle error
    }
  }
  return bIsWow64;
}

I have not yet tested whether CRegKey would open the correct version by default and also write to the correct place without setting any additional flags. Specifically, I am not sure whether Wow6432Node would be appended automatically.

Creating a shortcut

 Without losing too much words on this, creating a desktop shortcut is as simple as using QFile::link().

Rolling back

 User should be able to cancel the installation at any time and have its system intact. This means that we can't simply leave a bunch of files and registry entries on the system, we need to put everything back to the original state. I solved this problem by dividing each installation step in a separate method and then writing a rollback counterpart that does exactly the opposite. For every copied file I have a file removal and the same goes for every other modification. I also call the rollbacks if any of the installation steps fail.

If you are modifying existing files it is a good idea to first make a copy of the file and then place it back in case of a rollback.

Try to keep the system as intact as possible in case of a failure or cancellation.

Figuring out the system paths

 Let's say you want to copy your program files to C:/Program Files/Yourproject and you also want to create a desktop shortcut. You have two problems. First problem is that you don't know whether your folder should go to Program Files or Program Files (x86) because you don't know on what system you are. If your program is 32bit you know it should go to the (x86) but you don't know if that even exists – you might be on 32bit OS.

You also don't know the path to user's desktop. You have to use WINAPI and even that is a problem because Windows XP lacks some flags that newer systems have. I came up with the following function:

QString getProgramFiles() {
  TCHAR szPath[MAX_PATH];
  if (IsWinXP32()) {
      if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, szPath))) {
        return QString::fromWCharArray(szPath);
      }
      else {
        return "";
      }
  }
  else {
    if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_DEFAULT, szPath))) {
       return QString::fromWCharArray(szPath);
    }
    else {
      return "";
    }
  }
}

The culprit is CSIDL_PROGRAM_FILESX86 which returns an empty string on Windows XP.

For finding the desktop you can use CSIDL_DESKTOP flag.

Determining 32bit Windows XP can be done like this:

bool IsWinXP32() {
  DWORD version = GetVersion();
  DWORD major = (DWORD) (LOBYTE(LOWORD(version)));
  DWORD minor = (DWORD) (HIBYTE(LOWORD(version)));
  return ((major == 5) && (minor == 1));
}

 

The uninstaller

Making the uninstaller is quite an easy task except for the last part – removing uninstaller itself. A running process cannot delete itself so this is quite an annoying problem. A few examples can be seen here. What I ended up doing is basically calling cmd.exe and doing a rmdir (which contains the uninstaller:

QStringList a;
a << "/c"; //command
a << "rd"; //rmdir
a << "/s/q"; //with subdirectories and silently
a << projectpath;

QProcess::startDetached(getSystem32()+"\\cmd.exe", a);
QApplication::quit();

where getSystem32 returns the path to System32 using the above mentioned CSIDL flags. This pops up a cmd window for a brief period after the uninstaller quits by itself.

 

These are a few problems I encountered along the way when working on my own installer. it is really not that difficult but there are a few subtle problems which might get you along the way, some inside Qt and others in WINAPI. Hopefully this can save someone a few hours combating the same issues if you happen to land on this blog. :)

 

Cen
GitHub
Eurobattle.net
Lagabuse.com
Bnetdocs