<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oskars</title>
    <description>The latest articles on DEV Community by Oskars (@oskarspakers).</description>
    <link>https://dev.to/oskarspakers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F490583%2F010d10b2-098b-4a36-80f8-c1d3d7c9b111.png</url>
      <title>DEV Community: Oskars</title>
      <link>https://dev.to/oskarspakers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oskarspakers"/>
    <language>en</language>
    <item>
      <title>Efficient auditing for read operations</title>
      <dc:creator>Oskars</dc:creator>
      <pubDate>Wed, 20 Oct 2021 08:23:44 +0000</pubDate>
      <link>https://dev.to/oskarspakers/efficient-auditing-for-read-operations-4p3a</link>
      <guid>https://dev.to/oskarspakers/efficient-auditing-for-read-operations-4p3a</guid>
      <description>&lt;p&gt;Recently I ran into a scenario when the read operation was not performing well due to auditing requirements. If you need to persist an audit record on every read operation, writing to the database will most likely be the bottleneck.&lt;br&gt;
There are a few improvements listed below that can be done to improve performance. Improvements are ordered by subjective performance gain.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defer writing audit records using asynchronous queue&lt;/li&gt;
&lt;li&gt;Consume records from the queue in batches and do bulk inserts&lt;/li&gt;
&lt;li&gt;Separate read and write operations and read data from replica&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fxHFLqkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f19jb9qm3m9stgcyydv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fxHFLqkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f19jb9qm3m9stgcyydv5.png" alt="Diagram for asynchronous auditing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Detailed descriptions of steps in the flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User requests to get the status of something&lt;/li&gt;
&lt;li&gt;Application registers an event "getStatusCalled" that getStatus request has been performed.&lt;/li&gt;
&lt;li&gt;Application retrieves status from database standby node, thus not loading primary database node. The user receives a response&lt;/li&gt;
&lt;li&gt;Another application node (or same application node, but a different thread) periodically consumes "getStatusCalled" events in batches&lt;/li&gt;
&lt;li&gt;Application performs bulk insert to primary database node. Changes are replicated to the standby node using the database replication process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Have a feedback or improvement idea? Share it in a comment.&lt;/p&gt;

</description>
      <category>cqrs</category>
      <category>audit</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Import PBKDF2 hashed user passwords into Keycloak</title>
      <dc:creator>Oskars</dc:creator>
      <pubDate>Mon, 04 Jan 2021 14:02:27 +0000</pubDate>
      <link>https://dev.to/oskarspakers/import-pbkdf2-hashed-user-passwords-into-keycloak-571m</link>
      <guid>https://dev.to/oskarspakers/import-pbkdf2-hashed-user-passwords-into-keycloak-571m</guid>
      <description>&lt;p&gt;If you are in process of migrating to dedicated authentication provider Keycloak, you might need to retain original passwords from the source system.&lt;/p&gt;

&lt;p&gt;Since I spent some time on getting creating users with already hashed passwords to work with Keycloak, sharing the API call that is needed to achieve this. Tested with Keycloak 9.0.5&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST http://localhost:8080/auth/admin/realms/master/users
Authorization: Bearer {{access_token}}
Content-Type: application/json

{
  "enabled": true,
  "attributes": {},
  "username": "admin",
  "emailVerified": "",
  "credentials": [
    {
      "credentialData": "{\"hashIterations\": 27500,\"algorithm\": \"pbkdf2-sha256\"}",
      "secretData": "{\"salt\": \"x/bm4Y3DcuV9eU97ervkPA==\",\"value\": \"1u7BLvfSPxQFpwc5jpGSA+88EGl9pZYKhaZ8YPIu9N4=\"}",
      "type": "password"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here salt must be Base64 encoded value.&lt;br&gt;
An example creates a user with username "admin" and password "admin"&lt;/p&gt;

&lt;p&gt;There are also online tools available to encode raw passwords, for example, &lt;a href="https://8gwifi.org/pbkdf.jsp"&gt;https://8gwifi.org/pbkdf.jsp&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>password</category>
      <category>authentication</category>
      <category>pbkdf2</category>
    </item>
  </channel>
</rss>
