<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Sathya Bandara on Medium]]></title>
        <description><![CDATA[Stories by Sathya Bandara on Medium]]></description>
        <link>https://medium.com/@technospace?source=rss-e9b7ffb9b3d7------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*4rcjOJfV5gxqoIlV02NrxQ.jpeg</url>
            <title>Stories by Sathya Bandara on Medium</title>
            <link>https://medium.com/@technospace?source=rss-e9b7ffb9b3d7------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 13:14:18 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@technospace/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Automating Business Processes with Salesforce Flow Triggers]]></title>
            <link>https://technospace.medium.com/automating-business-processes-with-salesforce-flow-triggers-8d6c9f71df10?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/8d6c9f71df10</guid>
            <category><![CDATA[salesforce-development]]></category>
            <category><![CDATA[salesforce-rest-api]]></category>
            <category><![CDATA[salesforce-flow]]></category>
            <category><![CDATA[process-automation]]></category>
            <category><![CDATA[salesforce]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Tue, 20 Feb 2024 12:24:34 GMT</pubDate>
            <atom:updated>2024-02-20T12:24:34.632Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HUXf_E-5uTXq5ryWpPl4-A.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@halacious?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Hal Gatewood</a> on <a href="https://unsplash.com/photos/assorted-color-abstract-painting-tZc3vjPCk-Q?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><p>In the fast-paced world of business, effective and streamlined processes are the key to success. Salesforce, a powerful customer relationship management (CRM) platform, plays a pivotal role in helping businesses manage and organize their data.</p><p>Integrating with Salesforce is essential for businesses aiming to enhance customer relationships, improve efficiency, and gain valuable insights. Salesforce serves as a centralized hub for customer data, enabling organizations to make data-driven decisions, boost sales, and provide exceptional customer experiences.</p><p>One crucial aspect of maximizing the potential of Salesforce is automating business processes, and Salesforce Flow is one such robust solution for achieving this goal.</p><p>Salesforce Flows offer a declarative and user-friendly way to automate processes. Autolaunch Flows, in particular, can be triggered without user interaction, making them ideal for background processes. Autolaunch Flows can be invoked synchronously providing flexibility in implementation.</p><h4>Use Case: Daily Reset of Closed Support Tickets Count</h4><h4><strong>Scenario</strong></h4><p>Imagine a company providing customer support services where support agents resolve customer issues by closing support tickets. The business wants to track and analyze the daily performance of each support agent based on the number of tickets they close. To achieve this, a Salesforce custom field named “Closed Tickets Count” is used to store the total number of closed tickets for each agent.</p><h4><strong>Requirement</strong></h4><p>The business has a requirement to reset the “Closed Tickets Count” field to zero at the beginning of each day, ensuring that the daily count reflects the tickets closed on that specific day.</p><h4><strong>Implementation</strong></h4><p>To implement this use case, the company can utilize Salesforce Autolaunch Triggers along with Flows. The Autolaunch Flow would be designed to run daily and reset the “Closed Tickets Count” field for all support agents to zero.</p><h4><strong>Example Field</strong></h4><ul><li>Field Name: Closed Tickets Count (custom field on the User object)</li><li>Field Type: Number</li></ul><h4><strong>Process</strong></h4><p>The Autolaunch Flow is designed to query and update records based on specified criteria. In this case, it retrieves all user records (support agents) and sets the “Closed Tickets Count” field to zero.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*brAilEZ3W0FHI2UAEBo3xQ.png" /><figcaption>Creating an Autolaunch Flow via Flow Builder</figcaption></figure><h4>Execution</h4><p>To ensure that the “Closed Tickets Count” field is reset at the beginning of each day, there are two options.</p><ol><li>Schedule the trigger to run daily at a specific time</li><li>Invoke the trigger via the Salesforce REST API which facilitates you to streamline it with your existing business processes.</li></ol><pre>curl --location &#39;{salesforce_url}/actions/custom/flow/{flow_api_name}&#39; \<br>--header &#39;Content-Type: application/json&#39; \<br>--header &#39;Authorization: Bearer {token}&#39; \<br>--data &#39;{<br>    &quot;inputs&quot;: [{}]<br>}&#39;</pre><h4><strong>Result</strong></h4><p>At the end of each day, the “Closed Tickets Count” field for each support agent is automatically reset to zero, providing a clean slate for tracking the daily performance of support agents in resolving customer issues.</p><p>This example demonstrates how a business statistic, in this case, the count of closed support tickets, can be effectively reset daily to provide accurate and up-to-date insights into the daily performance of support agents.</p><h3>References</h3><p><a href="https://www.gradient.works/blog/salesforce-flow-best-practices-naming-conventions">Flow Naming Conventions</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8d6c9f71df10" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Choosing Between Indexing and Denormalization]]></title>
            <link>https://technospace.medium.com/choosing-between-indexing-and-denormalization-dbd18d32c05e?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/dbd18d32c05e</guid>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Sun, 11 Feb 2024 23:39:56 GMT</pubDate>
            <atom:updated>2024-02-11T23:39:56.764Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RLBfS0Bzlag9cobbDxLTqQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@rubaitulazad?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Rubaitul Azad</a> on <a href="https://unsplash.com/photos/text-Y9kOsyoWyaU?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><p>When it comes to optimizing your application’s performance, both indexing and denormalization are strategies used to enhance the underlying database’s performance, but they address different aspects of database design and usage.</p><h3><strong>Indexing</strong></h3><p>Indexes are useful for speeding up SELECT queries by providing a quick lookup mechanism for specific columns. They enhance read performance but can slow down write operations (INSERT, UPDATE, DELETE) as indexes need to be maintained.</p><p>Adding indexes to columns that are frequently used in WHERE clauses, JOIN conditions, or ORDER BY clauses can improve query performance. However, adding too many indexes may lead to increased storage requirements and potential overhead during write operations.</p><h4>Pros</h4><ul><li>Facilitate faster data retrieval by allowing the database engine to quickly locate the rows matching specific search criteria, resulting in improved query performance, especially for SELECT operations.</li><li>Enable quicker sorting and grouping of data, making operations like ORDER BY and GROUP BY more efficient.</li><li>Indexes can significantly speed up JOIN operations by providing efficient access paths to the joined tables.</li><li>Indexes can enforce uniqueness constraints on columns, ensuring data integrity and preventing duplicate entries.</li><li>The query optimizer can leverage indexes to generate more efficient query execution plans, leading to overall performance improvements.</li></ul><h4>Cons</h4><ul><li>Consume additional disk space, which can become significant, especially for large tables with multiple indexes.</li><li>They need to be updated whenever data is inserted, updated, or deleted, resulting in additional overhead on write operations (INSERT, UPDATE, DELETE).</li><li>As the number of indexes increases, the overhead on write operations also increases, potentially leading to degraded write performance, especially in write-intensive applications.</li><li>Regular maintenance tasks such as index rebuilds or reorganizations may be necessary to ensure optimal index performance, which can consume system resources and impact overall database maintenance.</li><li>Over time, indexes may become fragmented due to data modifications, leading to suboptimal performance. Regular maintenance is required to address index fragmentation.</li><li>Improper selection of indexes or creating too many indexes can lead to unnecessary overhead and potentially degrade overall database performance. It’s essential to carefully analyze query patterns and usage scenarios to determine the most beneficial indexes.</li></ul><h3><strong>Denormalization</strong></h3><p>Denormalization involves storing redundant data in a table to avoid costly JOIN operations, especially in situations where read performance is critical and data modification is infrequent. It is often employed in data warehousing or reporting scenarios.</p><p>Denormalization can improve query performance but comes at the cost of increased storage space and potential data inconsistency (due to redundant data). It requires careful management to keep redundant data synchronized.</p><p>Denormalization involves storing redundant data in a table to reduce the need for complex JOIN operations and improve query performance.</p><h4><strong>Pros</strong></h4><ul><li>Can significantly enhance read performance, especially in scenarios with complex queries and aggregations.</li><li>Minimizes the need for JOINs, which can be expensive in terms of processing time.</li></ul><h4><strong>Cons</strong></h4><ul><li>Increases storage requirements due to redundant data.</li><li>Requires careful management to ensure data consistency between normalized and denormalized versions.</li><li>Write operations may become more complex and potentially slower.</li></ul><h3><strong>Factors to consider when deciding</strong></h3><h4><strong>Query Patterns</strong></h4><ul><li>If your application has complex queries with multiple JOINs and aggregations, denormalization may be considered to reduce the need for JOINs.</li><li>If your queries involve simple lookups and filtering, indexes might be more suitable.</li></ul><h4><strong>Write vs. Read Operations</strong></h4><ul><li>If your application is write-intensive, adding too many indexes can slow down write operations. In such cases, denormalization might be a better option to optimize read performance.</li><li>If your application is read-intensive and write operations are infrequent, adding indexes may be more beneficial.</li></ul><h4><strong>Data Modification Frequency</strong></h4><ul><li>If your data undergoes frequent updates, inserts, or deletes, excessive indexes may result in overhead during write operations. Denormalization might be preferred in such cases for better write performance.</li></ul><h4><strong>Storage and Resource Constraints</strong></h4><ul><li>Consider the available storage space and system resources. Denormalization increases storage requirements, while indexes consume additional disk space.</li></ul><h4><strong>Data Consistency Requirements:</strong></h4><ul><li>Denormalization may lead to redundancy and potential inconsistencies. If data consistency is crucial, you may need to carefully manage denormalized data or consider alternative solutions.</li></ul><p>In many cases, a balanced approach involving a combination of indexing and denormalization might be the most effective solution. It’s important to analyze the specific use case, monitor performance, and iterate on your database design based on actual performance metrics and user requirements.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dbd18d32c05e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Streamlining Subscription Management with Stripe Schedules]]></title>
            <link>https://technospace.medium.com/streamlining-subscription-management-with-stripe-schedules-b97c27aaa35f?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/b97c27aaa35f</guid>
            <category><![CDATA[stripe-integration]]></category>
            <category><![CDATA[stripe-payment]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[stripe]]></category>
            <category><![CDATA[scheduling]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Fri, 17 Nov 2023 17:03:34 GMT</pubDate>
            <atom:updated>2024-02-04T10:04:43.659Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MSJYLo6x2ZPjjUpGxxLnVw.jpeg" /><figcaption>Image Credits: <a href="https://chartmogul.com/blog/why-is-stripe-so-popular/">https://chartmogul.com/blog/why-is-stripe-so-popular/</a></figcaption></figure><p>Subscription-based services have become crucial for businesses these days since they provide a reliable source of revenue while offering convenience to customers. However, managing these subscriptions can become increasingly complex, especially when it comes to handling future changes to subscription plans. Stripe, one of the most powerful payment infrastructures in the world, facilitates this requirement through Stripe Subscription Schedules. In this blog post, we’ll explore how Stripe Schedules can help you automate future changes to subscriptions and enhance your subscription management process.</p><h4>What are Stripe Schedules?</h4><p>Stripe Schedules is a feature that allows businesses to automate subscription-related events, such as plan changes, trial periods, and billing cycles, in advance. It offers a straightforward and efficient way to schedule and execute changes to subscriptions without manual intervention, reducing the administrative burden on you and ensuring a seamless experience for your customers.</p><h4>Common Use-cases of Stripe Schedules</h4><ul><li>Schedule subscription activation</li><li>Automate upgrades and downgrades</li><li>Schedule subscription cancellations</li><li>Manage installment plans</li></ul><p>A comprehensive list of Stripe Schedule use-cases with sample codes can be found <a href="https://stripe.com/docs/billing/subscriptions/subscription-schedules/use-cases">here</a>.</p><h4>Automating Subscription Upgrades and Downgrades</h4><p>One of the most common use cases for Stripe Schedules is automating subscription plan changes. Whether a customer wants to upgrade immediately, to a higher-tier plan with additional features or downgrade to a more affordable option on a future date, Stripe Schedules can handle these requests with ease.</p><p>For example, if a customer requests a downgrade from a premium plan to a basic plan that starts at the beginning of the next billing cycle, you can set up a schedule to automatically switch their subscription when the next billing period begins. This ensures a smooth transition for the customer and minimizes the chances of manual errors.</p><p>Below steps demonstrate how you can integrate with Stripe Schedules API, to schedule a downgrade to be activated on the start date of the next billing period.</p><ol><li><a href="https://stripe.com/docs/billing/subscriptions/subscription-schedules#managing">Generate a Subscription Schedule</a>. You have following 2 options for this.<br> *Create a new Subscription with a Schedule.</li></ol><pre>curl https://api.stripe.com/v1/subscription_schedules \<br>  -u &quot;sk_test_4eC39HqLyjWDarjtT1zdp7d:&quot; \<br>  -d customer=cus_GBHHxuvBvO26Ea \<br>  -d start_date=now \<br>  -d end_behavior=release \<br>  -d &quot;phases[0][items][0][price]&quot;=price_1GqNdGAJVYItwOKqEHb \<br>  -d &quot;phases[0][items][0][quantity]&quot;=1 \<br>  -d &quot;phases[0][iterations]&quot;=12</pre><p>* Generate a Subscription Schedule from an existing Subscription.</p><pre>curl -X POST https://api.stripe.com/v1/subscription_schedules \ <br>-u &quot;sk_test_4eC39HqLyjWDarjtT1zdp7dc:&quot; \ <br>-d from_subscription=sub_GB98WOvaRAWPl6</pre><p>2. Fetch the created Subscription Schedule and <a href="https://stripe.com/docs/billing/subscriptions/subscription-schedules#updating">update</a> it to add an additional phase.</p><pre>curl -X POST https://api.stripe.com/v1/subscription_schedules/sub_sched_1FSRtAILNmKrzH4z9scwDpeL \<br>  -u &quot;sk_test_4eC39HqLyjWDarjtT1zdp7dc:&quot; \<br>  -d &quot;phases[0][plans][0][price]&quot;=&quot;price_1GqNdGAJVYItwOKqEHb&quot; \<br>  -d &quot;phases[0][plans][0][quantity]&quot;=1 \<br>  -d &quot;phases[0][start_date]&quot;=1577865600 \<br>  -d &quot;phases[0][end_date]&quot;=1580544000 \<br>  -d &quot;phases[1][plans][0][price]&quot;=&quot;price_1GqNdGAJVYItwOKqEHb&quot; \<br>  -d &quot;phases[1][plans][0][quantity]&quot;=1 \<br>  -d &quot;phases[1][iterations]&quot;=1 </pre><p>Here, we need to pass in two phases in the update request — The first phase should be the existing current phase on the Subscription Schedule. The values should be passed in as it is, without any modifications. The second phase should represent the subscription once it’s been downgraded. iterations set to 1 indicate that the downgrade will be activated on the start date of the next billing cycle.</p><p>Depending on your requirements, you can also set proration_behavior, tax_rates and discount_codes</p><p>3. In case you want to remove this schedule from the subscription, you can simply <a href="http://stripe.com/docs/api/subscription_schedules/release">release the schedule</a>. This will only cancel the future downgrade.</p><pre>curl -X POST https://api.stripe.com/v1/subscription_schedules/sub_sched_1OCUR82eZvKYlo2CGBx2JGbV/release \ <br>-u &quot;sk_test_4eC39HqLyjWDarjtT1zdp7dc:&quot;</pre><p>4. In order to view all the schedules of a subscription customer. You can use the below request.</p><pre>curl https://api.stripe.com/v1/subscription_schedules<br>-u &quot;sk_test_4eC39HqLyjWDarjtT1zdp7dc:&quot; \<br>-d &quot;customer=cus_OoOlYtLOckfZc5&quot;</pre><p>Managing subscriptions and ensuring a smooth experience for your customers can be a challenging task, especially as your business grows. Stripe Schedules offers a solution that streamlines subscription management, automates future changes, and enhances the overall customer experience.</p><p>By taking advantage of Stripe Schedules, you can reduce administrative overhead, increase revenue predictability, and minimize errors. Ultimately, this feature allows you to focus on what matters most: growing your business and providing value to your customers.</p><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b97c27aaa35f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Secure Spring Boot Application with OpenID Connect and Role Based Authorization]]></title>
            <link>https://technospace.medium.com/secure-spring-boot-application-with-openid-connect-and-role-based-authorization-efaeceb014c7?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/efaeceb014c7</guid>
            <category><![CDATA[spring-security]]></category>
            <category><![CDATA[role-based-authorization]]></category>
            <category><![CDATA[keycloak]]></category>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[openid-connect]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Sat, 20 May 2023 10:11:50 GMT</pubDate>
            <atom:updated>2024-02-04T12:57:42.616Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*StBXF2TS9cep9555I2ehyQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@kaffeebart?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Kaffeebart</a> on <a href="https://unsplash.com/photos/a-close-up-of-a-padlock-on-a-door-KrPulSdUetk?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><p>In this article, I hope to give a step by step approach on how you can secure your Spring Boot application with OpenID Connect Login and Role Based Authorization. I will here be using Keycloak as the Identity Provider however you are free to use another Identity and Access Management Solution in place. The solution given here will work with any other identity provider as well with few changes.</p><p>For the scope of this tutorial, I will omit the steps on setting up the Keycloak server and Spring Boot application. I will add links on official guidelines on how you can set up those under <strong>References</strong> section.</p><h4>Use case</h4><p>For simplicity let’s assume we have a Spring Boot application with a Rest Controller to view customers and their payment information. There will be 2 endpoints with GET mapping.</p><ul><li><strong>/customers</strong> will list basic information about a customers available in the system. This endpoint allows a user to access customer information with a GET request. We need to ensure security for this endpoint such that only users who successfully authenticated can view the endpoint.</li><li><strong>/payments</strong> With this endpoint users can view customer specific payment information. Since this endpoint displays confidential information, we need to enforce an additional level of security. Hence, in addition to having user authentication, we also need to ensure that users with certain privileges (admin access) can view this endpoint data. Therefore, we will be enforcing role based authorization such that only an authenticated user with <strong>customer-service-admin</strong> role will be allowed to access the endpoint.</li></ul><h4>Configuring Keycloak for OpenID Connect Login</h4><p>Create a new realm in your Keycloak server. Let’s use <strong>my-realm</strong> as the realm name.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HH6noTTiXT-4F0M0O6ABSA.png" /></figure><p>Configure a new OpenID Connect client as shown in below image. Let’s use <strong>customer-service-client</strong> as the Client ID.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YTNZuUyUvdr_IF1jXog47w.png" /></figure><p>Make sure to enable the options ‘<strong>Standard flow</strong>’ and ‘<strong>Client authentication</strong>’</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Rwv2TKWl4aPs-WsqpiNyaw.png" /></figure><p>Configure a client role from the client role tab. Role name: <strong>customer-service-admin</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Dmc3uYY9ZzyK0s0NbA_YqA.png" /></figure><p>Create 2 new users. Let’s use usernames <strong>peter</strong> and <strong>ben</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4wrHuScwfuutPaebSwM_oA.png" /></figure><p>For the first user (peter) assign the client role that we created in a previous step.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UEP4cd8fWR-BsH3wc8rpzA.png" /></figure><p>Navigate to Client Scopes -&gt; Roles -&gt; Client Roles -&gt; Scopes -&gt; Enable the option ‘<strong>Add to ID token</strong>’</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B1tZO54VYfKorhAPxXOjEA.png" /></figure><p>These are the steps required to configure Keycloak for securing your application. Now, if all the configurations are successful, you can try out authorization code flow and obtain an access token from authorization code grant type using a tool like postman or curl and make sure the standard flow is working as expected. If you decode the id_token using a tool like <a href="https://jwt.io/">jwt.io</a>, you should be able to find the client roles under the <strong>resource_access</strong> field in the token as shown below. (When you authenticate with user peter).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*DwnwvcLSuVbLpu5KOH_i3w.png" /></figure><h4>Configuring Spring Boot Application</h4><p>We need to use <strong>spring-boot-starter-security</strong> and <strong>spring-boot-starter-oauth2-client</strong> libraries to configure OpenID Connect login for the Spring Boot application. Hence, add the following to your pom file.</p><pre>&lt;dependency&gt;<br> &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br> &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br><br>&lt;dependency&gt;<br> &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br> &lt;artifactId&gt;spring-boot-starter-oauth2-client&lt;/artifactId&gt;<br>&lt;/dependency&gt;</pre><p>Next, we need to update <strong>application.properties</strong> file in order to communicate with the Keycloak server using OpenID Connect protocol. Add the below configs to the property file. Make sure to update the values with your application specific settings.</p><pre>spring.security.oauth2.client.registration.keycloak.client-id=customer-service-client<br>spring.security.oauth2.client.registration.keycloak.client-secret=cUYL7M81Vm9CKYrxFTqUTtB2FIVqckzM<br>spring.security.oauth2.client.registration.keycloak.scope=openid,profile,roles<br>spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code<br>spring.security.oauth2.client.registration.keycloak.redirect-uri=http://localhost:8001/login/oauth2/code/keycloak<br>spring.security.oauth2.client.provider.keycloak.issuer-uri=http://localhost:8080/realms/my-realm</pre><p>Now, we need to override the default HTTP Security configuration in Spring to enforce OpenID Connect Login for the users. This is possible with the registration of a <strong>SecurityFilterChain</strong> bean as shown below.</p><pre>@Configuration<br>@EnableWebSecurity<br>public class ConfigSecurity {<br><br> @Bean<br> public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {<br><br>  http.authorizeHttpRequests()<br> .requestMatchers(&quot;/customers/**&quot;).authenticated()<br> .and().oauth2Login();<br> return http.build();<br> }<br>}</pre><p>Now if you try to access the /customers endpoint, your browser will be redirected to Keycloak login page. With any of the above created users (peter or ben) you should be able to successfully authenticate.</p><p>Next, we need to configure role based authorization for the /payments endpoint as per our second requirement.</p><p>Spring internally uses <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/core/GrantedAuthority.html"><strong>GrantedAuthorities</strong></a> for access control. By default, Spring Framework will generate <strong>SimpleGrantedAuthories</strong> based on the values available in the ‘scope’ claim of a JWT by prepending them with SCOPE_ prefix. (e.g. SCOPE_openid, SCOPE_email). Those can be used for authorizing requests, such as in <strong>hasRole</strong> or <strong>hasAuthority</strong> methods.</p><p>In our case, we need a way to extract the client roles from the JWT, and generate GrantedAuthorities for those. For this, I will be implementing a GrantedAuthoritiesMapper as shown below.</p><pre>public class GrantedAuthoritiesMapperImpl implements GrantedAuthoritiesMapper {<br><br>    private static final String RESOURCE_ACCESS = &quot;resource_access&quot;;<br>    private static final String ROLES = &quot;roles&quot;;<br>    private static final String ROLE_PREFIX = &quot;ROLE_&quot;;<br><br>    @Value(&quot;${spring.security.oauth2.client.registration.keycloak.client-id}&quot;)<br>    private String deliveryServiceClientId;<br><br>    @Override<br>    public Collection&lt;? extends GrantedAuthority&gt; mapAuthorities(Collection&lt;? extends GrantedAuthority&gt; authorities) {<br><br>        Set&lt;GrantedAuthority&gt; mappedAuthorities = new HashSet&lt;&gt;();<br><br>        authorities.forEach(authority -&gt; {<br>            if (authority instanceof OidcUserAuthority oidcUserAuthority) {<br>                // Map the claims found in idToken to one or more GrantedAuthority.<br>                OidcIdToken idToken = oidcUserAuthority.getIdToken();<br>                mappedAuthorities.addAll(extractClientRoles(idToken));<br>            }<br>        });<br>        return mappedAuthorities;<br>    }<br><br>    private Collection&lt;GrantedAuthority&gt; extractClientRoles(OidcIdToken idToken) {<br><br>        Map&lt;String, Object&gt; resourceAccess = idToken.getClaim(RESOURCE_ACCESS);<br>        Map&lt;String, Object&gt; resource;<br>        Collection&lt;String&gt; resourceRoles;<br>        if (deliveryServiceClientId == null || resourceAccess == null<br>                || (resource = (Map&lt;String, Object&gt;) resourceAccess.get(deliveryServiceClientId)) == null<br>                || (resourceRoles = (Collection&lt;String&gt;) resource.get(ROLES)) == null) {<br>            return Set.of();<br>        }<br>        return resourceRoles.stream()<br>                .map(role -&gt; new SimpleGrantedAuthority(ROLE_PREFIX + role))<br>                .collect(Collectors.toSet());<br>    }<br>}</pre><p>Next, we need to register a bean for the GrantedAuthoritiesMapper class and update the securityFilterChain to enforce Role based Access Control for the /payments endpoint as shown below.</p><pre>@Configuration<br>@EnableWebSecurity<br>public class ConfigSecurity {<br>    @Bean<br>    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {<br><br>        http.authorizeHttpRequests()<br>                .requestMatchers(HttpMethod.GET, &quot;/payments/**&quot;).hasRole(&quot;customer-service-admin&quot;)<br>                .requestMatchers(&quot;/customers/**&quot;).authenticated()<br>                .and().oauth2Login().userInfoEndpoint()<br>                .userAuthoritiesMapper(this.userAuthoritiesMapper());<br>        return http.build();<br>    }<br>    @Bean<br>    public GrantedAuthoritiesMapper userAuthoritiesMapper() {<br>  return new GrantedAuthoritiesMapperImpl();<br>    }<br>}</pre><p>Now if you try to access the /payments endpoint, your browser will be redirected to Keycloak login page as before. But only the user with the admin privileges (peter) will be able to view the contents of this endpoint.</p><h4><strong>References</strong></h4><ul><li><a href="https://www.keycloak.org/docs/18.0/server_installation/">https://www.keycloak.org/docs/18.0/server_installation/</a></li><li><a href="https://spring.io/guides/gs/spring-boot/">https://spring.io/guides/gs/spring-boot/</a></li></ul><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=efaeceb014c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SQL Injections Demystified]]></title>
            <link>https://technospace.medium.com/sql-injections-demystified-66b184851c4f?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/66b184851c4f</guid>
            <category><![CDATA[sql-injection]]></category>
            <category><![CDATA[sql]]></category>
            <category><![CDATA[software-vulnerabilities]]></category>
            <category><![CDATA[sql-injection-attack]]></category>
            <category><![CDATA[sql-injection-prevention]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Mon, 11 Jul 2022 15:20:20 GMT</pubDate>
            <atom:updated>2024-02-03T18:56:27.649Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*7R9yV79MH20MOvKO" /><figcaption>Photo by <a href="https://unsplash.com/@diana_pole">diana_pole</a> on <a href="https://unsplash.com/">unsplash</a></figcaption></figure><p>SQL which stands for Structured Query Language is a programming language that was specifically designed to communicate with relational databases. It is a “command” that is sent to the database in order to retrieve a set of records, insert/update records or perform a certain action.</p><ul><li>For example: SELECT name, cost FROM products. This returns the name and cost of all products.</li><li>We can be more specific by adding a WHERE clause: SELECT name, cost FROM products WHERE id = 2. This will return the name and cost of the product with an id equal to 2.</li></ul><h3>What is an SQL Injection (SQLi) ?</h3><p>A SQL injection is a technique used to gain unauthorized access to a database by manipulating SQL queries used in an application. Malicious users can use this type of attack to get access to protected resources such as user credentials, or execute malicious SQL statements in order to manipulate the application.</p><p>If SQL queries are used in your application in such a way that, an attacker can inject their own SQL into the query, it allows space for SQLi attacks on your application.</p><p>Most common way to perform an SQLi on a vulnerable SQL query is to use the UNION clause to combine the results of multiple SELECT statements.</p><p>For example assume that following query was used to retrieve the list products from the products table by using the id from a direct user input field of the application.</p><pre>SELECT name, cost FROM products WHERE id = ? </pre><p>An attacker can use the UNION clause in the input field along with the id in order to obtain records from a restricted table in the database.</p><pre>SELECT name, cost FROM products WHERE id = 2 UNION SELECT username, password FROM users</pre><p>The above query will combine the two queries and return them in one result set.</p><pre>+-------------------------+---------------------------+</pre><pre>| name                    | cost                      |</pre><pre>+-------------------------+---------------------------+</pre><pre>| L86 Fingerprint Scanner | 73.55                     |</pre><pre>| user1                   | Secret123                 |</pre><pre>| user2                   | myPaswd                   |</pre><pre>+-------------------------+---------------------------+</pre><p>This way, an attacker will get the credentials of all the users in the database and he can use those to perform malicious actions on the application.</p><h3>Testing an Application for SQLi Vulnerability</h3><p>The best way to test for SQL injections is to follow a structured approach such as follows.</p><h4><strong>Step 1: Determine number of columns</strong></h4><p>SQL assumes the select statements on both sides of the UNION clause return the same number of columns. In order to determine how many columns the 1st query uses, we can start with querying for 1 column, then 2 columns etc in the user input field of the application’s page that is susceptible to SQLi. We use numbers so we do not have to guess table names or column names. You keep adding numbers until we see the results of the 1st query on the application page again (make sure no error messages, no empty pages are shown).</p><ul><li>2 UNION SELECT 1</li><li>2 UNION SELECT 1,2</li><li>…</li><li>2 UNION SELECT 1,2,3,4,5</li></ul><h4><strong>Step 2: Determine location of columns in output</strong></h4><p>The application now receives the result of the first query and the numbers returned by the second query. Since we’ll never want to look at the results of the first query, we change that first number into a number that never exists: -1</p><pre>-1 UNION SELECT 1,2,3,4,5</pre><h4>Step 3: Use INFORMATION_SCHEMA to retrieve the column and table names</h4><p>Now we can simply ask the database to show us all table and column names by using the meta table INFORMATION_SCHEMA.columns!</p><pre>-1 UNION SELECT 1,table_name,column_name,4,5 FROM INFORMATION_SCHEMA.columns</pre><p>Note that we still need to match the number of columns with the 1st select statement.</p><p>Once we get the list of table names and the column names, we can access data in any of those tables in the database.</p><p>Assume the user credentials are available in a table called Users under column names username and password. Then we can list the data as shown below.</p><pre>-1 UNION SELECT 1,username,password,4,5 FROM Users</pre><h3>How to Prevent SQLi in Your Application?</h3><p>Following lists some of the techniques you can use to prevent SQLi vulnerabilities in your application. These can be used with any kind of programming language with any kind of database system.</p><ul><li>Using Prepared Statements (with Parameterized SQL Queries)</li><li>Using Properly Constructed Stored Procedures</li><li>Allow-list Input Validation</li><li>Escaping All User Supplied Input</li></ul><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66b184851c4f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Configure Flyway for Seamless Database Migration]]></title>
            <link>https://technospace.medium.com/how-to-configure-flyway-for-seamless-database-migration-6cd52dc3619c?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/6cd52dc3619c</guid>
            <category><![CDATA[flyway]]></category>
            <category><![CDATA[database-migration]]></category>
            <category><![CDATA[mysql]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[flywaydb]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Tue, 22 Feb 2022 20:23:39 GMT</pubDate>
            <atom:updated>2022-02-22T20:23:39.204Z</atom:updated>
            <content:encoded><![CDATA[<p>Flyway is a tool that supports database migrations on multiple types of relational databases. It is open-source and licensed under Apache 2.0 License.</p><h4>What are the Advantages?</h4><ul><li>Facilitates seamless updates to a database schema from one version to another as an application evolves with the code.</li><li>Keeps a record of the updates applied on a schema in a separate table. By default this table is called SCHEMA_VERSION.</li><li>Couple database updates to an application’s deployment pipeline and make sure that those changes are properly applied.</li><li>Keeps track of which changes were already applied and which were not.</li></ul><p>In Flyway, updates or changes made to a database schema are known as <strong>migrations</strong>.</p><h4>Migration Types</h4><ul><li>SQL script based migrations: For straightforward schema changes.</li><li>Java based migrations: For advanced database transformations.</li></ul><h4>Naming Conventions</h4><p>Migrations should be named in the default naming conventions for Flyway to identify them properly.</p><p>For sql based migrations the naming convention is V&lt;version-number&gt;__&lt;description&gt;.sql</p><p>Example: V2__Add_new_table.sql</p><p>For Java based migrations, lass name must comply with the pattern V&lt;version-number&gt;__&lt;description&gt;</p><p>Example: V2__Add_new_table</p><p>Also there are mainly 3 ways to configure and run Flyway for your application</p><ul><li>Integrate flyway directly into your application.</li><li>Run it as a stand-alone tool as part of your build process.</li><li>Execute manually from the command line (using the command line client)</li></ul><p>In this post, I will show how you can easily integrate Flyway in to a Java application.</p><p>Flyway is implemented in Java and hence the integration is quite straight-forward.</p><p><strong>Prerequisites</strong></p><p>Configure a database of your own choice. I will be using a MySQL database for this demonstration.</p><p><strong>Steps</strong></p><ol><li>Create a maven based Java project and add the flyway-core dependency under dependencies section in your pom.xml file.</li></ol><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;org.flywaydb&lt;/groupId&gt;<br>    &lt;artifactId&gt;flyway-core&lt;/artifactId&gt;<br>    &lt;version&gt;8.5.0&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>2. Inside the build section of POM file, we need to configure the Flyway maven plugin. Also we need to configure the database and Java Connector for the specific database type, as class path dependencies of the plugin.</p><pre>&lt;plugin&gt;<br>    &lt;groupId&gt;org.flywaydb&lt;/groupId&gt;<br>    &lt;artifactId&gt;flyway-maven-plugin&lt;/artifactId&gt;<br>    &lt;version&gt;8.5.0&lt;/version&gt;<br>    &lt;configuration&gt;<br>        &lt;url&gt;jdbc:mysql://localhost:3306/flyway_demo&lt;/url&gt;<br>        &lt;user&gt;test&lt;/user&gt;<br>        &lt;password&gt;test&lt;/password&gt;<br>        &lt;locations&gt;<br>            &lt;location&gt;classpath:db/migration&lt;/location&gt;<br>        &lt;/locations&gt;<br>    &lt;/configuration&gt;<br>    &lt;dependencies&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;org.flywaydb&lt;/groupId&gt;<br>            &lt;artifactId&gt;flyway-mysql&lt;/artifactId&gt;<br>            &lt;version&gt;8.2.2&lt;/version&gt;<br>        &lt;/dependency&gt;<br>        &lt;dependency&gt;<br>            &lt;groupId&gt;mysql&lt;/groupId&gt;<br>            &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;<br>            &lt;version&gt;8.0.12&lt;/version&gt;<br>        &lt;/dependency&gt;<br>    &lt;/dependencies&gt;<br>&lt;/plugin&gt;</pre><p>You need to change the following parameters in the above configuration to suit your integration.</p><ul><li>&lt;url&gt; : This should be your database connection URL.</li><li>&lt;user&gt; : Username for the database connection.</li><li>&lt;password&gt; : Password for the database connection.</li><li>The two dependencies added under &lt;dependencies&gt; section inside the &lt;plugin&gt; should be the database and database Java connector of the particular type of database you are using. I have used the corresponding dependencies to connect to a MySQL database.</li></ul><p>3. Create a folder named db.migrations inside src/main/resources folder of your project. Here we will be defining all the migrations. For this project, I will be using SQL script based migrations.</p><p>4. Inside db.migrations folder create a new file called V1__add_user_table.sql and add the following code to create our initial table.</p><pre>create table USER (<br>    ID int not null,<br>    NAME varchar(100) not null<br>);</pre><p>5. Now execute the following command from the root of your project.</p><pre>mvn flyway:migrate</pre><p>6. After the above command is successful, you should be able to see a table called USER created in your database.</p><p>7. Let’s add a new migration inside db.migrations with the name V2__add_new_column_email.sql Here we will be altering the schema of the previously created table by adding a new column.</p><pre>ALTER TABLE USER ADD EMAIL varchar(200);</pre><p>8. Now when browse the USER table again, you should be able to see that a new column with the title EMAIL is available in the schema.</p><p>Similarly, you can add new scripts to modify the schema and insert data to your tables. However make sure to version them properly with the correct naming convention.</p><p>I hope you got an idea on what is Flyway and how it can be integrated easily to your project. <a href="https://github.com/emswbandara/FlywayDemo">Here</a> you can refer the complete source code of my project. For additional information you can refer to <a href="https://flywaydb.org/documentation/">Official Flyway Documentation</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6cd52dc3619c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hello, Kotlin!]]></title>
            <link>https://technospace.medium.com/hello-kotlin-10003117fcac?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/10003117fcac</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[kotlin-beginners]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Sun, 30 Jan 2022 21:30:17 GMT</pubDate>
            <atom:updated>2024-02-03T18:57:35.427Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kJV3fz5P5BAIo0ExF9oI3g.jpeg" /><figcaption>Image Credits: <a href="http://unsplash.com/">unsplash.com</a></figcaption></figure><p>I was working as a java software engineer for more than 4 years. Recently I joined a firm that uses Kotlin instead of Java and I have been learning Kotlin for the past few weeks.</p><p>Learning Kotlin has been fun and interesting. Also, I feel it is fairly easy for a Java developer to learn Kotlin because the syntax is almost similar but Kotlin is less verbose than Java. From my post, I want to share with you some cool features I learned about Kotlin.</p><h4>Background</h4><p>Kotlin is an open-source, statically-typed programming language that features both object-oriented and functional programming paradigms. It is the primary development language in Android.</p><p>Now let’s dive into some unique features in Kotlin.</p><h4>Single Type System</h4><p>A type system is a set of rules that determine the types of a programming language construct.</p><p>Kotlin comes along with a very powerful typing system. Unlike Java, Kotlin does not have primitive types. Hence, Kotlin’s type system is solely on objects.</p><p>Following are the built-in types in Kotlin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/987/1*ryWV4kRi1V1B_sZWupRO9Q.jpeg" /><figcaption>Image Credits: <a href="https://speakerdeck.com/npryce/the-kotlin-type-hierarchy-from-top-to-bottom?slide=9">https://speakerdeck.com/npryce/the-kotlin-type-hierarchy-from-top-to-bottom?slide=9</a></figcaption></figure><p>Other than above, users can define their own types by means of Classes, Interfaces, Enums.</p><h4>Type Inference</h4><p>Kotlin is a strongly typed language that supports Type Inference. Kotlin compiler can automatically identify the data type of the variable or the return-type of a function even if you don’t explicitly specify it.</p><p>For example, in Kotlin you can declare a variable in 2 ways.</p><ol><li>var num : Int = 2</li><li>var num = 2</li></ol><p>Note that in the second method, you didn’t have to specify the type of the variable because Kotlin is able to infer the type based on the value assigned to the variable.</p><p>This is the same case for the return type of functions.</p><h4>Smart Casts</h4><p>Kotlin compiler can perform type casts automatically in the following cases.</p><ul><li>Casting from a supertype to a subtype</li></ul><pre>val object: Any = &quot;test string&quot;<br>if(object is String) {<br>// Here, object is automatically casted to String sub-type.<br>   println(object.length) <br>}</pre><ul><li>Casting from nullable types to their non-nullable counterpart</li></ul><pre>var firstName: String? = &quot;test string&quot;<br>if(firstName != null) { // Smart cast.<br>   print(firstName.length)<br>}</pre><h4>Null safety</h4><p>In Kotlin, types are non-null by default. To allow a variable to hold null, we can declare a variable with the nullable operator (?).</p><pre>var firstName: String = null // This will give compilation error</pre><pre>var firstName: String? = null // Ok</pre><p>Now, Kotlin compiler will warn us whenever we try to access variables declared as nullable.</p><h4>Elvis Operator</h4><p>The Elvis operator (?:) is designed specifically to handle null cases. It will return a non-null value or a default value when the variable is null.</p><pre>val name = firstName ?: &quot;Empty&quot;</pre><p>You can also throw an exception if the variable is null.</p><pre>val name = firstName ?: throw Exception(&quot;Invalid name&quot;)</pre><h4>Top-level Functions &amp; Variables</h4><p>Top-level functions are functions inside a Kotlin package that are defined outside of any class, object, or interface definition. These functions can be invoked directly, without the reference to a class or an object. Top-level variables are the same as top-level functions. Variables are defined outside a class definition in Kotlin.</p><pre>fun main() { <br>   println(&quot;Hello, Kotlin!&quot;)<br> }</pre><p>In Kotlin, variables are of two types.</p><ul><li>Read-Only<br>val the keyword is used for read-only variables. This is similar to the final keyword in Java meaning the variable cannot be reassigned once initialized.</li><li>Mutable<br>var the keyword is used for mutable variables in Kotlin. When a variable is defined as var, it is possible to re-assign its value in a latter part of the code.</li></ul><h4>Single Expression Definitions</h4><p>Kotlin gives us the capability to define functions as a single expression for direct operations. Basically, a single-expression function is a function where a single expression is assigned to the function, and the expression’s evaluated value is returned when this function is called.</p><pre>fun getGreeting() = &quot;Hello, Kotlin&quot;</pre><p>The above is a single expression function that takes no arguments and return “Hello, Kotlin” string whenever it is called.</p><h4>String Templates</h4><p>String templates in Kotlin are String literals that can contain embedded expressions.</p><pre>val message = &quot;Hello $variable&quot;</pre><p>Unlike in Java, a String template can contain logic as well.</p><pre>val message = &quot;Hello, ${if(variable != null) variable else &quot;Unknown&quot;}&quot;</pre><h4>Named Arguments</h4><p>Kotlin allows you to specify the names of arguments that you’re passing to the function. This can be helpful when a function has many arguments.</p><pre>fun fun_name(name1: data_type, name2: data_type )</pre><h4>Default Arguments</h4><p>you can provide default values to parameters in the function definition. When invoking the function, you can omit passing arguments if they are not different from the default ones.</p><pre>fun printGreeting(greeting:String = &quot;Hello&quot;, name:String =&quot;Kotlin&quot;) {<br>   println(&quot;$greeting, $name&quot;)<br>}</pre><p>This allows to configure and re-use functions and objects by leveraging these default and named arguments syntax.</p><h4>Companion Objects</h4><p>In the scenario where you do not want to give direct access to the instantiation of a particular class, you can define a companion object inside that class. By declaring a companion object, you can access the properties and functions of the original class using the class name without instantiation. This is useful when implementing the factory design pattern in Kotlin.</p><pre>class CompanionClass {<br><br>    companion object CompanionObject {<br><br>    }<br>}<br>val object = CompanionClass.CompanionObject</pre><h4>Data classes</h4><p>Data classes are defined for the purpose of holding data. The Kotlin compiler automatically generates the following functions for them.</p><ul><li>toString()</li><li>equals()</li><li>hashCode()</li><li>copy()</li><li>componentN()</li></ul><p>Example of a data class declaration.</p><pre>data class Employee (<br>  val id: String,<br>  val name: String?<br>)</pre><h4>Extensions</h4><p>Kotlin provides the ability to extend a class with new functionality without having to inherit from the class. You can extend functions as well as properties of a class.</p><p>This is highly useful when you want to incorporate new functions/properties for a class from a third-party library that you cannot modify.</p><p>For extending properties, initializers cannot be used. You have to override the getters/setters of those properties. You can also define new properties for existing classes.</p><h4>Higher-Order Functions</h4><p>A higher-order function is a function that takes functions as parameters or returns a function. By default, Kotlin functions are first-class. First-class functions can be stored in variables and data structures and can be passed as arguments to and returned from other higher-order functions.</p><h4>Function Types</h4><p>In Kotlin, function types are used to store functions as variables. An example is shown below.</p><pre>val greet = fun() { println(&quot;Hello, Kotlin!&quot;) }</pre><p>I hope you got a high-level overview of some of the useful features of Kotlin. For detailed information please refer the <a href="https://kotlinlang.org/docs/home.html">official Kotlin documentation</a>. Thank you for reading!</p><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10003117fcac" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Best practices in Identifying the Authorization Context of an OAuth2 Token — WSO2 Identity Server]]></title>
            <link>https://medium.com/identity-beyond-borders/best-practices-in-identifying-the-authorization-context-of-an-oauth2-token-wso2-identity-server-e1040be1b764?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/e1040be1b764</guid>
            <category><![CDATA[introspection]]></category>
            <category><![CDATA[wso2is]]></category>
            <category><![CDATA[wso2]]></category>
            <category><![CDATA[oauth2]]></category>
            <category><![CDATA[oidc]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Tue, 04 Feb 2020 06:28:47 GMT</pubDate>
            <atom:updated>2024-02-03T18:58:37.181Z</atom:updated>
            <content:encoded><![CDATA[<h3>Best practices in Identifying the Authorization Context of an OAuth2 Token</h3><p>In this post, we’ll discuss the best practices of identifying the authorized user of an access token and what approach we recommend in doing so.</p><p><a href="https://wso2.com/identity-and-access-management/">WSO2 Identity Server</a> supports OAuth2 and OpenID Connect frameworks that define standard protocols on authorizing third-party applications when accessing user identities such that access to unauthorized content is restricted.</p><p>Within this framework, any third application or a resource server should use a valid token to retrieve user attributes from the authorization server. According to the specification, the user should have given consent for these applications beforehand. The spec suggests the following two approaches on how an application should request user information after a valid access token is acquired from the authorization server.</p><h4>id-token</h4><p>Here user needs to authenticate and authorize the application to access his claims. And claims will be sent in the id-token in JWT format, based on the consent given during the authentication process.</p><h4>user-info endpoint</h4><p>An application can invoke the user-info endpoint with a valid access token requesting for a set of claims of the user who authorized the token. This token should contain the required scope to access the user claims. The authorization server will consider the token scope, user’s consent and then issue the claim set.</p><p>In both of the above methods, the application/resource server gets access to the user’s claims(resources) because the user(resource owner) has provided consent to do or the respective application has the authorization to invoke it.</p><p>In addition to spec-compliant approaches, we also provide the capability to retrieve authorized user information via the following approaches.</p><h4>Token Validation SOAP Service</h4><p>This was our legacy approach before we had the implementation of user-info endpoint or id-token.</p><h4>Introspection Endpoint</h4><p>Here an application authenticates and can retrieve any claim.</p><p>Above two options are disabled in the product out of the box. Anyone who needs to enable it should enable the following global config in &lt;IS_HOME&gt;/repository/conf/identity/identity.xml file.</p><pre>&lt;AuthorizationContextTokenGeneration&gt;</pre><pre><strong>&lt;Enabled&gt;true&lt;/Enabled&gt; </strong>&lt;TokenGeneratorImplClass&gt;org.wso2.carbon.identity.oauth2.authcontext.JWTTokenGenerator&lt;/TokenGeneratorImplClass&gt; &lt;ClaimsRetrieverImplClass&gt;org.wso2.carbon.identity.oauth2.authcontext.DefaultClaimsRetriever&lt;/ClaimsRetrieverImplClass&gt;&lt;ConsumerDialectURI&gt;http://wso2.org/claims&lt;/ConsumerDialectURI&gt;&lt;SignatureAlgorithm&gt;SHA256withRSA&lt;/SignatureAlgorithm&gt;&lt;AuthorizationContextTTL&gt;15&lt;/AuthorizationContextTTL&gt;</pre><pre>&lt;/AuthorizationContextTokenGeneration&gt;</pre><p>Why we have disabled it in the product is due to the severe security implications it imposes on <a href="https://wso2.com/identity-and-access-management/">WSO2</a> when it is acting as the authorization server. We do not recommend enabling it as well. I will explain these implications in detail below.</p><h4>Self-Contained Access Token</h4><p>This is another way, how an application can obtain user information from token endpoint in the form of a JWT instead of an opaque token. In a self-contained-type, information associated with an access token is embedded in the access token itself in addition to user claims.</p><h4>Why retrieving user-claims via TokenValidationService/Introspection is NOT recommended?</h4><p>Introspection endpoint and TokenValidationService can be called by any party who has the authorization to invoke it. But that doesn’t mean they have the authorization to view the particular user’s claims. They are only authorized to see the metadata of the access token.</p><p>Therefore if we enable user-claim retrieval via these options, it allows the resource server and any other third-party application who is in possession of a valid access token, to get any claim of the user and there is no restriction. The respective application may not be authorized to do so.</p><h4>What about self-contained access token?</h4><p>Here we have a plus point when compared to other two. It is that an application can retrieve user information only after the user successfully authenticates and provides consent to retrieve his claims. However since the token is self-contained and can be verified without invoking the authorization server, there is no way to invalidate the token in case it gets counterfeited, until the token expires.</p><p>Due to the above-mentioned implications of these non-standard alternative approaches, we are recommending only the OIDC spec-compliant approaches to retrieve authorized user information of an access token. That is either via the id-token or user-info endpoint.</p><p>Thanks for reading!</p><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e1040be1b764" width="1" height="1" alt=""><hr><p><a href="https://medium.com/identity-beyond-borders/best-practices-in-identifying-the-authorization-context-of-an-oauth2-token-wso2-identity-server-e1040be1b764">Best practices in Identifying the Authorization Context of an OAuth2 Token — WSO2 Identity Server</a> was originally published in <a href="https://medium.com/identity-beyond-borders">Identity Beyond Borders</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An Introduction to Helm Charts]]></title>
            <link>https://technospace.medium.com/an-introduction-to-helm-charts-41be1544370c?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/41be1544370c</guid>
            <category><![CDATA[helm]]></category>
            <category><![CDATA[helm-chart]]></category>
            <category><![CDATA[deployment]]></category>
            <category><![CDATA[introduction]]></category>
            <category><![CDATA[kubernetes]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Sun, 26 Jan 2020 12:00:52 GMT</pubDate>
            <atom:updated>2024-02-03T19:01:00.999Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nvLbU9trxyL4O6hpxUoBUg.jpeg" /></figure><h4>What is Helm?</h4><p>When deploying an application on Kubernetes, it is required to define and manage several Kubernetes resources such as pods, services, deployments, and replicasets. Each of these require to write a group of manifest files in YAML format. In the context of a complex application deployment it becomes a difficult task to maintain several manifest files for each of these resources. Furthermore, templating the manifest files and providing configuration parameters externally, can become crucial which will allow to customize the deployments. Dependency management and version control are some other important factors to consider as well. This is where Helm plays a vital role in automating the process of installing, configuring and upgrading complex Kubernetes applications.</p><p>Helm is a package manager for Kubernetes. It allows developers and operators to easily package, configure, and deploy applications and services on Kubernetes clusters. Helm packages contain Kubernetes object definitions. With Helm, configuration settings are isolated from manifest files. This allows to template and customize settings without changing the entire manifest file.</p><h4>Helm Architecture</h4><p>Helm uses a packaging format called <strong>charts</strong>. A chart is a collection of files that describes a related set of Kubernetes resources.</p><p>In Helm, there are mainly three notions.</p><ol><li><em>chart</em> : A bundle of information necessary to create an instance of a Kubernetes application.</li><li><em>config</em> : contains configuration information that can be merged into a packaged chart to create a releasable object.</li><li><em>release : </em>A running instance of a <em>chart</em>, combined with a specific <em>config</em>.</li></ol><p>Helm is implemented in Go programming language and the same binary executable can function as a client (Helm) or a server (Tiller).</p><h4>Helm Client</h4><p>Helm client is a command line tool for managing charts. It’s main functionalities are as follows.</p><ul><li>Developing local charts</li><li>Managing repositories</li><li>Interacting with the Tiller server</li><li>Sending charts to be installed in Kubernetes cluster</li><li>Asking for information about releases</li><li>Requesting upgrading or uninstalling of existing releases in cluster</li><li>Serve local charts via HTTP</li></ul><h4>Tiller Server</h4><p>Tiller is the server component of Helm that runs on the Kubernetes cluster. It is responsible for managing releases of helm charts. It interacts with both helm client and interface of Kubernetes API server. It handles the configuration and deployment of Helm releases on the cluster.</p><p>Tiller processes a chart to generate Kubernetes resource manifests. Tiller then installs the release into the cluster. Tiller stores each release as a Kubernetes <strong>ConfigMap</strong>.</p><p>Main functionalities are as follows.</p><ul><li>Listening for incoming requests from the Helm client</li><li>Combining a chart and configuration to build a release</li><li>Installing charts into Kubernetes, and then tracking the subsequent release</li><li>Upgrading and uninstalling charts by interacting with Kubernetes</li></ul><h4>Charts</h4><p>Helm packages are called <em>charts</em>, and they consist of mainly YAML configuration files. Following is the basic directory structure of a chart.</p><pre>package-name/<br>  charts/<br>  templates/<br>  Chart.yaml<br>  LICENSE<br>  README.md<br>  requirements.yaml<br>  values.yaml</pre><p>You can find an example of above structure in WSO2 Identity Server Helm resources at [1]</p><p>These directories and files have the following functions.</p><ul><li><strong>charts/: </strong>Manually managed chart dependencies can be placed in this directory. However recommendation is to use the requirement.yaml file to link dependencies dynamically.</li><li><strong>templates/:</strong> This directory contains template files that are combined with configuration values. Configuration values can be read from either values.yaml file or command line. These are then rendered into Kubernetes manifests.</li><li><strong>Chart.yaml:</strong> A YAML file with metadata about the chart. E.g. chart name, version, maintainer etc.</li><li><strong>LICENSE:</strong> A plaintext license for the chart.</li><li><strong>README.md:</strong> A readme file which includes the user guide.</li><li><strong>requirements.yaml:</strong> A YAML file that lists the chart’s dependencies.</li><li><strong>values.yaml:</strong> A YAML file of default configuration values for the chart.</li></ul><h4>Repositories</h4><p>A Helm chart repository is an HTTP site that serves an index.yaml file and packaged charts. These files can be served by any web server, object storage service, or a static site host such as GitHub Pages.</p><p>Helm comes pre-configured with a default chart repository, identified by the name <strong>stable</strong>. This repository points to a Google Storage bucket at https://kubernetes-charts.storage.googleapis.com. In addition, you can add any external third party repositories. As such any organization can run an operate its own Helm repository.</p><h4>Releases</h4><p>When a Helm chart is deployed in a Kubernetes cluster, it is known as a Helm release. This is an instance of a chart that is running in the cluster. Helm automatically maintains a version history of the releases. We can easily get back to any previous state with helm rollback command. Same chart can be deployed multiple times. This result in multiple releases as well.</p><p>[1] <a href="https://github.com/wso2/kubernetes-is/tree/master/advanced/is-pattern-1">https://github.com/wso2/kubernetes-is/tree/master/advanced/is-pattern-1</a></p><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=41be1544370c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CSRF in IDP Initiated OpenID Connect]]></title>
            <link>https://technospace.medium.com/csrf-in-idp-initiated-openid-connect-7a2873420e86?source=rss-e9b7ffb9b3d7------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a2873420e86</guid>
            <category><![CDATA[csrf]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[oauth]]></category>
            <category><![CDATA[openid-connect]]></category>
            <dc:creator><![CDATA[Sathya Bandara]]></dc:creator>
            <pubDate>Wed, 24 Jul 2019 05:31:41 GMT</pubDate>
            <atom:updated>2024-02-03T19:34:18.827Z</atom:updated>
            <content:encoded><![CDATA[<h3>Preventing Cross-Site Request Forgery in Identity Provider-Initiated OpenID Connect</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wvTFWe90AgzqFdaf2LBBZg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@towfiqu999999?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Towfiqu barbhuiy</a> on <a href="https://unsplash.com/photos/a-golden-padlock-sitting-on-top-of-a-keyboard-FnA5pAzqhMM?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a></figcaption></figure><p>CSRF (Cross-Site Request Forgery) can allow an attacker to coerce a user into unknowingly and unintentionally dispatch responses to an application. By tricking a user into following a link, for example a link which submits a form to a vulnerable application which does not detect CSRF an attacker can have a user unknowingly perform operations on the application.</p><p>Generally, CSRF protection can be provided by the use of a CSRF token. In order to protect against CSRF, this token should be a cryptographically random nonce which is tied to the user’s session. This token can be submitted with the requests as an invisible form field or cookie which ensures that a user cannot submit a form without first visiting the form page. Every request that contain this value must be checked to ensure that it matches the expected value. In the event the value does not match, this can be flagged as suspicious behavior, as it is a clear indication of malicious activities.</p><p>In OIDC flow, CSRF attacks can occur against client callback URL when an attacker injects its own authorization code or access token, which can result in the client using an access token associated with the attacker’s protected resources rather than the victim’s. This is described in ‘OAuth 2.0 Threat Model and Security Considerations’ spec [1] as follows.</p><blockquote><em>An attacker could authorize an authorization “code” to their own protected resources on an authorization server. He then aborts the redirect flow back to the client on his device and tricks the victim into executing the redirect back to the client. The client receives the redirect, fetches the token(s) from the authorization server, and associates the victim’s client session with the resources accessible using the token.</em></blockquote><blockquote><strong><em>Impact</em></strong><em>: The user accesses resources on behalf of the attacker. The effective impact depends on the type of resource accessed. For example, the user may upload private items to an attacker’s resources. Or, when using OAuth in 3rd-party login scenarios, the user may associate his client account with the attacker’s identity at the external Identity Provider. In this way, the attacker could easily access the victim’s data at the client by logging in from another device with his credentials at the external Identity Provider.</em></blockquote><p>In OIDC flow, ‘state’ parameter is used to mitigate CSRF attacks. In order to prevent CSRF attacks on callback, client needs to implement CSRF protection by checking that the state parameter exists in the user’s session when an authorization code response arrives in exchange for the access token to the client callback URL. The state parameter in this design should a be key to a session attribute in the initiator user’s session with the client application. In typical scenario, this is done by cryptographically binding the value of user’s browser cookie and client ID to session parameter.</p><p>However, in the case where OIDC flow is initiated by IDP, IDP cannot prevent the CSRF attacks because the state parameter needs to be generated and managed by the client in order to correlate the state with the application user’s session.</p><p>One possible solution which can be performed by the client to mitigate CSRF attacks in IDP initiated OIDC requests, is by verifying the ‘Referer’ headers of the incoming HTTP requests.</p><p>This is further elaborated in [2] section 6. Following is an overview of the solution mentioned in the paper.</p><blockquote><em>When the RP receives an authorization response, it first retrieve the identity of the IdP from redirect uri and then checks that the domain in the Referer header is either the RP Domain or the IdP domain. If the domain of the Referer header is one of these two values,then the RP knows this is a genuine authorization response coming from the IdP; otherwise, the RP should discard this HTTP message and send an error page to the user.</em></blockquote><blockquote><em>As an example of how this might work in practice, suppose a web attacker puts a link </em><a href="https://rp.com/AIdP-callback?code=[code_belongs_to_attacker_generated_by_AIdP"><em>https://rp.com/AIdP-callback?code=[code_belongs_to_attacker_generated_by_AIdP</em></a><em>] on attacker.com to try to launch a CSRF attack against the redirect uri RP registered with IdP. The HTTP message of the attack re-quest will contain a Referer header which points to attacker.com. The RP is able to detect this is an attack message by comparing the identity of the IdP or its own domain with the domain in the Referer header.</em></blockquote><h4>References</h4><p>[1] <a href="https://tools.ietf.org/html/rfc6819#section-4.4.1.8">https://tools.ietf.org/html/rfc6819#section-4.4.1.8</a><br> [2] <a href="https://pdfs.semanticscholar.org/03b1/bb33db610486c2f81a2532107b0a17a631ca.pdf">https://pdfs.semanticscholar.org/03b1/bb33db610486c2f81a2532107b0a17a631ca.pdf</a></p><figure><a href="https://www.buymeacoffee.com/technospace"><img alt="" src="https://cdn-images-1.medium.com/max/170/1*bk_C8Um34KavCkO2yzMCZg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a2873420e86" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>