Thursday, July 2, 2026

Github Action to build an artefact - Java application (.war file generation)

 

# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
name: AscentOne Portal Backend - Maven
permissions:
actions: read
contents: read
on:
workflow_dispatch:
inputs:
command:
description: 'Which environment to build'
required: true
default: 'test'
type: choice
options:
- test
- production
jobs:
# build-frontend:
# uses: ./.github/workflows/AscentOne.yml
build:
runs-on: ubuntu-latest
environment: AscentOne.${{ github.event.inputs.command || 'test' }}
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
# Determine which branch to use in config repo
- name: Resolve config repo branch
id: config_branch
env:
BRANCH_NAME: ${{ github.ref_name }}
TOKEN: ${{ secrets.ACCESSTOKEN }}
run: |
if git ls-remote --exit-code --heads \
https://x-access-token:${TOKEN}@github.com/AscentOne-Ltd/AscentOne-cicd-templates.git \
"${BRANCH_NAME}" >/dev/null 2>&1; then
echo "ref=${BRANCH_NAME}" >> $GITHUB_OUTPUT
echo "Using branch ${BRANCH_NAME}"
else
echo "ref=main" >> $GITHUB_OUTPUT
echo "Branch ${BRANCH_NAME} not found. Using main."
fi
# ✅ Pull config repo
- name: Checkout config repo
uses: actions/checkout@v4
with:
repository: AscentOne-Ltd/AscentOne-cicd-templates
token: ${{ secrets.CICDACCESSTOKEN }}
path: config-repo
ref: ${{ steps.config_branch.outputs.ref }}
# ✅ Copy configs
- name: Copy config files
working-directory: AscentOneBackend
run: |
ENV=${{ github.event.inputs.command || 'test' }}
cp ../config-repo/templates/applications/AscentOne//$ENV/application.yml src/main/resources/application.yml
cp ../config-repo/templates/applications/AscentOne/$ENV/application-prod.yml src/main/resources/application-prod.yml
cp ../config-repo/templates/applications/AscentOne/$ENV/application-int.yml src/main/resources/application-int.yml
cp ../config-repo/templates/applications/AscentOne/$ENV/application-dev.yml src/main/resources/application-dev.yml
cp ../config-repo/templates/applications/AscentOne/$ENV/logback.xml src/main/resources/logback.xml
- name: Download frontend artifact
uses: dawidd6/action-download-artifact@v3
with:
workflow: ascentOneAngularfrontend.yml
name: application-ascentOneAngularfrontend-${{ github.event.inputs.command }}
path: ascentOneAngularfrontend-new

- name: Copy malfunction new frontend into backend resource folder
run: |
rm -rf AscentOneBackend/src/main/webapp/resources/html*
mkdir -p AscentOneBackend/src/main/webapp/resources/html
cp -r ascentOneAngularfrontend-new/malfunction/. AscentOneBackend/src/main/webapp/resources/html
- name: Build with Maven
working-directory: AscentOneBackend
run: mvn clean package -DskipTests
- name: Upload AscentOneBackend WAR artifact
uses: actions/upload-artifact@v4
with:
name: AscentOneBackend.war
path: AscentOneBackend/target/*.war

Monday, April 27, 2026

Security Vulnerability - Regular Expression Denial of Service (ReDoS)

NVD - CVE-2025-69873

 1. Backtracking (in the context of regular expressions and algorithms) is a trial‑and‑error process where the engine tries one possible path, and if that path fails, it goes back (“backtracks”) and tries another.

Think of backtracking like this:

“Try option A.
If it doesn’t work, rewind and try option B.
If that doesn’t work, rewind further and try option C…”

This is fine when there are only a few options.
It becomes dangerous when the number of options grows exponentially.


What is catastrophic backtracking?

Catastrophic backtracking happens when:

  • A regex has nested repetition or ambiguity
  • The engine must try an enormous number of paths
  • Matching time becomes extremely slow

Example :

^(a+)+$


Why it’s bad:

  • a+ already repeats
  • Wrapping it in ()+ creates nested repetition
  • The engine keeps retrying the same matches in different groupings

Just adding one more character to the input can double execution time.


What is ReDoS

A ReDoS vulnerability stands for Regular Expression Denial of Service. It is a type of Denial‑of‑Service (DoS) attack that exploits how some regular expressions are evaluated.

ReDoS happens when a specially crafted input causes a regular expression to take an extremely long time to evaluate, consuming CPU and making an application unresponsive.


Why backtracking causes ReDoS

Backtracking itself is normal.
It becomes a vulnerability when attackers can control the input.

Attack flow:

  1. Attacker sends specially crafted input
  2. Regex engine enters massive backtracking
  3. CPU usage spikes
  4. Application becomes unresponsive

In Node.js or single‑threaded environments:

  • One slow regex = entire server blocked

What makes it a vulnerability?

ReDoS becomes a security vulnerability when:

  1. A regex is evaluated on untrusted input
  2. The regex or the input can be influenced by an attacker
  3. The regex runs on a shared or single-threaded resource (e.g. Node.js event loop)

An attacker can then:

  • Send a single request
  • Tie up CPU
  • Block all other users

Getting access token from Microsoft using Powershell

 


$tenantId   = "<your-tenant-id>"

$clientId   = "<yourclient-id>"

$client_secret= "<client-secret>"

$scope      = "api://<your-client-id>/.default"

$grant_type = "client_credentials"


$tokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"


$body = @{

    client_id      = "$clientId"

    client_secret  = "$client_secret"

    scope          =  "$scope"

    grant_type     = "client_credentials"

}


$graphToken = Invoke-RestMethod `

    -Method POST `

    -Uri $tokenUrl `

    -ContentType "application/x-www-form-urlencoded" `

    -Body $body



$token =  $graphToken.access_token


Tuesday, November 25, 2025

Top Ways to Mock your server for testing/building Angular Project

 #1. Using Proxy 


Add a file proxy.conf.json

{

  "/rest": {
    "target": "http://tca-test-exs.doaminname:8080",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug",
     "headers": {
      "Authorization": "Basic ZW1zdmljcm06OTclb3BzY2sh"
      }
    }
}

Run angular CLI using ng serve --proxy-config proxy.conf.json



#2. Exposing a brand-new Node Server Fake API:

Install
npm install -g json-server

Add a folder "server" and add two files : server.js and db.json
const app = require('express')();

app.get('/product2/portalService/getUsers', (req, res) => {
  res.json([
    { id: 1, name: 'Node Mock IAP' }
  ]);
});
app.listen(3000);

Run that server. js in a new powershell window in VS Code







Wednesday, November 5, 2025

Powershell script to get Keyvault token using Powershell - Windows and Linux

 $os = [System.Environment]::OSVersion.Platform

$runningLinux = $false


$Host.UI.WriteLine("Running on $os")


if("Unix" -eq $os)

{

    $runningLinux = $true

}

az login --service-principal   -u <principle-guid>   -p <active-secret>   --tenant <token-guid>

$Host.UI.WriteLine("Login was successful for az cli and now going to get the token from https://vault.azure.net")

$token=az account get-access-token --resource https://vault.azure.net --query accessToken -o tsv


$Host.UI.WriteLine("Received token successful $token")

 

# Define headers properly (PowerShell expects a hash table)

$headers = @{

    "Authorization" = "Bearer $token"

}

 

$Host.UI.WriteLine("Start calling nslook on kvdmpprodae001.vault.azure.net")

if(!$runningLinux)

{

    Resolve-DnsName kvdmpprodae001.vault.azure.net

} else

{

    nslookup kvdmpprodae001.vault.azure.net

}

$Host.UI.WriteLine("End calling nslook on kvdmpprodae001.vault.azure.net")


$Host.UI.WriteLine("Start calling curl on https://kvdmpprodae001.vault.azure.net")

curl -v https://kvdmpprodae001.vault.azure.net

$Host.UI.WriteLine("End calling curl on https://kvdmpprodae001.vault.azure.net")

 

if($runningLinux)

{

    $Host.UI.WriteLine("Start calling curl on https://kvdmpprodae001.vault.azure.net/secrets/<your-key-name>?api-version=7.3")

    curl -v -H "Authorization: Bearer $token" --trace-ascii trace.log https://kvdmpprodae001.vault.azure.net/secrets/<your-key-name>?api-version=7.3

    $Host.UI.WriteLine("End calling curl on https://kvdmpprodae001.vault.azure.net/secrets/<your-key-name>?api-version=7.3")

}

 

# Call Key Vault REST API


$Host.UI.WriteLine("Invoking the webrequest with the token received")

$response = Invoke-WebRequest -Uri "https://kvdmpprodae001.vault.azure.net/secrets/<your-key-name>?api-version=7.3" -Headers $headers

 

    $Host.UI.WriteLine("Now printing the vault access")

# Output response

$response.Content



Once you created above .ps1 file. Run it using Powershell in Windows or install powershell in Linux and run using :

pwsh <filename>.ps1

Wednesday, October 22, 2025

Powershell script to bring news from news Feeds and create a nice looking HTML page.



# ===== DailyNews.ps1 =====




# RSS feed URLs

$techFeeds = @(

"https://techcrunch.com/feed/",

"https://feeds.arstechnica.com/arstechnica/index"

)

$propertyFeeds = @(

"https://www.abc.net.au/news/feed/52278/rss.xml"

)




# Output HTML file

$outputFile = "C:\temp\DailyNews.html"




# Current date

$date = (Get-Date).ToString("dddd, MMM dd yyyy")




# Function to fetch feed items

function Get-FeedItems {

param($url)




Write-Host $url

try {

$rss = [xml](Invoke-WebRequest -Uri $url -UseBasicParsing -ErrorAction Stop).Content

$items = @()

foreach ($item in $rss.rss.channel.item | Select-Object -First 5) {

$items += [PSCustomObject]@{

Title = $item.title

Link = $item.link

PubDate = $item.pubDate

Source = $rss.rss.channel.title

}

}

return $items

} catch {

Write-Host "⚠️ Could not fetch: $url"

return @([PSCustomObject]@{

Title = "⚠️ Could not fetch"

Link = $url

PubDate = ""

Source = ""

})

}

}




# Fetch items

$techNews = @()

foreach ($feed in $techFeeds) {

$techNews += Get-FeedItems $feed

}




$propertyNews = @()

foreach ($feed in $propertyFeeds) {

$propertyNews += Get-FeedItems $feed

}







# Build HTML content

$html = @"

<html>

<head>

<title>📰 Daily Tech & Property News - $date</title>

<style>

body { font-family: Segoe UI, Arial; background: #f9fafb; color: #333; margin: 20px; }

h1, h2 { color: #2a7ae2; }

a { text-decoration: none; color: #0078d7; }

a:hover { text-decoration: underline; }

section { margin-bottom: 40px; }

.article { margin: 8px 0; }

footer { margin-top: 40px; font-size: 12px; color: #777; }

</style>

</head>

<body>

<h1>📰 Daily Tech & Property News</h1>

<p><b>Date:</b> $date</p>




<section>

<h2>🏠 Property News</h2>

<ul>

"@




foreach ($item in $propertyNews) {

$html += "<li class='article'><a href='$($item.Link)' target='_blank'>$($item.Title)</a></li>`n"

}




$html += @"

</ul>

</section>




<section>

<h2>💻 Tech News</h2>

<ul>

"@




foreach ($item in $techNews) {

$html += "<li class='article'><a href='$($item.Link)' target='_blank'>$($item.Title)</a></li>`n"

}




$html += @"

</ul>

</section>




<footer>Generated automatically by PowerShell – $date</footer>

</body></html>

"@




# Save HTML

$html | Out-File -FilePath $outputFile -Encoding utf8

Write-Host "✅ HTML News Summary saved to $outputFile"

Tuesday, September 2, 2025

Springboot - Authenticating Microsoft Token

 A JWT has 3 parts (Base64URL encoded, separated by dots):

<header>.<payload>.<signature>



Create a POSTMan POST request to get MS token:

POST https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token

Send the below params in x-www.-form-urlencoded:


client_id: <id of application>
client_secret: <generated secret of that app>
score: api://<tenant-id>/.default
grant_type : client_credentials


The response would be :

{
    "token_type": "Bearer",
    "expires_in": 3599,
    "ext_expires_in": 3599,
    "access_token": "eyJ0eXAiOiJKV1QiL................."
}



Copy that access_token and get ready for actual API request:

https://<applicationurl>/<apiname>/<operationname>

For ex
https://tap/tcaservice/myapi

Send that access token as Bearer Token under Authentication Header

Here is the code for Token validation

@Component
public class MicrosoftTokenFilter extends OncePerRequestFilter {

    private final JwtDecoder jwtDecoder;

    public MicrosoftTokenFilter(@Value("${azure.ad.tenant-id}") String tenantId) {
        //String issuerUri = "https://login.microsoftonline.com/" + tenantId + "/v2.0";
        String issuerUri = "https://sts.windows.net/" + tenantId + "/";
        this.jwtDecoder = JwtDecoders.fromIssuerLocation(issuerUri);
    }

 @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        logger.info("Starting MicrosoftTokenFilter");
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);

            logger.info(" token = " + token);
            try {
                Jwt jwt = jwtDecoder.decode(token);

                SetupAuthentication(jwt);

            } catch (Exception e) {
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid Microsoft token");
                return;
            }
        }

        filterChain.doFilter(request, response);
    }

    private void SetupAuthentication(Jwt jwt) {

            Map<String, Object> claims = jwt.getClaims();

            String name = "";
            String email = "";
            String orgCode = "";
            boolean isAuthUser = false;
            String environment = "TEST";
            String orgName = "";

            List<Role> roles = new ArrayList<Role>();
            for ( Map.Entry<String,Object> claim : claims.entrySet()) {

                if (claim.getKey().equals("EMAIL")) {
                    email = claim.getValue().toString();
                }
            }

            //set faked
            name = "Naas api";
            email = "vkumar@austroads.gov.au";
            orgCode = "Naas";
            isAuthUser = true;
            environment = "TEST";
            orgName = "Austroads";

            if (isAuthUser) {
                User user = new User();
                user.setFirstName("");
                user.setLastName(name);
                user.setEmail(email);
                user.setOrganisationCode(orgCode);
                user.setRoles(roles);
                user.setOrganisationName(orgName);


                Authentication authentication = createAuthentication(jwt, user, environment);
                setAuthentication(authentication);


                logger.info("Authorities set in context:" + SecurityContextHolder.getContext().getAuthentication().getAuthorities());

            }
    }

    private Authentication createAuthentication(Jwt jwt, User user, String environment) {      
        List authList = new ArrayList();  
        authList.add(new SimpleGrantedAuthority("TEST_MyAdminRole");
    JwtAuthenticationToken usertoken = new JwtAuthenticationToken(jwt, authList);
        return usertoken;      
    }

    private void setAuthentication(Authentication authentication) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authentication);
        SecurityContextHolder.setContext(context);
    }

}