Author Archives: admin

Fixing SAML Authentication Failure After FortiGate Upgrade with Microsoft Entra ID – Firewall Authentication Failed

A quick post on what broke after a FortiGate firmware upgrade—and the one setting that fixed it.

After upgrading a FortiGate firewall to the latest firmware, I ran into an unexpected problem:
SAML authentication suddenly stopped working for users signing in via
Microsoft Entra ID (formerly Azure AD). The configuration looked intact—certificates were present,
the SAML setup was unchanged—yet logins kept failing.
Forticlient users, will get Firewall Authentication Failed



It wasn’t a lost configuration or a certificate mismatch. It turned out to be a change in
how SAML assertions are validated in the newest FortiGate versions when
Microsoft Entra ID is the Identity Provider (IdP).

The Root Cause
The latest FortiGate firmware expects the IdP to sign both the SAML response and the SAML assertion.
If your Entra ID configuration only signs the response (which used to be sufficient), authentication will fail
after the upgrade.

The Fix (Microsoft Entra ID setting)

  • Open the Microsoft Entra admin center and go to your Enterprise application for FortiGate.
  • Navigate to Single sign-on → SAML Certificates → SAML Signing Certificate → Edit.
  • Under Signing option, select: Sign SAML response and assertion.
  • Save the change and test authentication again.
  • Once this option was enabled, users were able to authenticate successfully again.

    Why This Matters
    Requiring signatures on both the response and the assertion strengthens the integrity of the SAML flow:
    FortiGate can verify not only the envelope (response) but also the identity claims (assertion).
    This improves security, but it may catch existing deployments by surprise after an upgrade.

    Takeaway

    • If SAML breaks after a FortiGate firmware upgrade with Entra ID as IdP, don’t assume your configuration is lost.
    • Enable “Sign SAML response and assertion” in Microsoft Entra ID for the affected application.
    • Re-test sign-in—authentication should start working immediately.

    Reference
    Fortinet community article on post-upgrade SAML issues:
    Troubleshooting Tip – SAML Authentication fails after firmware upgrade

    Tip: If you manage multiple FortiGate clusters, note this requirement in your upgrade checklist to avoid surprise outages.

    Linux Docker contrainer and PRTG

    Simple script to monitor that all docker container is running, and report the status back to PRTG
    It return 1 if the docker is running, or else it will return 0.

    #!/bin/bash
    echo  "<prtg>"
    #dockerlist_arr=( $(docker ps -a) )
    readarray -t dockerlist_arr < <( docker ps -a | awk '{print $NF}' | tail -n +2 )
    for i in "${dockerlist_arr[@]}"
    do
       echo "<result>"
       echo "<channel>$i</channel>"
       if [ "$( docker container inspect -f '{{.State.Running}}' $i )" = "true" ]; then
            echo "<value>1</value>"
       else
            echo "<value>0</value>"
       fi
       echo "<LimitMode>1</LimitMode>"
       echo "<LimitMaxError>1</LimitMaxError>"
       echo "<LimitMinError>1</LimitMinError>"
       echo "</result>"
    # or do whatever with individual element of the array
    done
    echo "</prtg>"
    

    VMware and Powershell

    Broadcom the owner and vendor of VMWare have release a new powershell module, called VCF.PowerCLI instead of the vmware PowerCLI.
    If you computer is online, you can installed it with the powershell command Install-Module

    Install-Module -Name VCF.PowerCLI

    If yours computer/server is not online, you can download it from another computer, and installed it though the manuel way, please look here: https://developer.broadcom.com/powercli/installation-guide

    When upgradering from Vmware PowerCLI – Throubleshooting
    If you allready have Vmware PowerCLI installed on the computer, you may encounter the following error when trying to install VCF.PowerCLI

    PackageManagement\Install-Package : The following commands are already available on this system

    This happens because some of the commandlets which are part of the PowerCLI SDK have been moved to other modules. To resolve the conflict you need to add the AllowClobber parameter to Install-Module

    Install-Module -Name VCF.PowerCLI -AllowClobber

    AllowClobber overrides warning messages about installation conflicts about existing commands on a computer. Overwrites existing commands that have the same name as commands being installed by a module. AllowClobber and Force can be used together in an Install-Module command.

    Extend a debian/ubuntu partition on a virtual machine.

    This is howto extend a virtual machine drive running Debian / Ubuntu
    1. First you need to make sure that there are no snapshot of the VM. If there are snapshot, you can extend the drive in either vmWare or Hyper-V.
    2. If the server is running Hyper-v, you can’t extend an IDE drive. If it are an IDE device, you need to turn of the computer first.
    3. Make sure that the partition is not an extended partition. If it are you can still extend it, but then this guide won’t work for you. Run fdisk -l /dev/sdX
    4. Make sure that the drive is not an LVM storage. Then you can’t used this guide.

    The above image, showes that there are an extend partition.

    After you have checked, that there are no snapshot, the drive is not an IDE and it the last partition on the drive that needed to extend. Then goes to yours hypervisor and extend the drive, with the amount of storage you will like to have the drive extend with.

    Then back on the linux server, install the package cloud-guest-utils, with this command

    apt install cloud-guest-utils

    Then run these commands:

    ls /sys/class/scsi_host/ | while read host ; do echo "- - -" > /sys/class/scsi_host/$host/scan ; done
    ls /sys/class/scsi_device/ | while read host ; do echo 1 > /sys/class/scsi_device/$host/device/rescan ; done

    This will rescan the SCSI bus for new drive and drive extension.

    After you have run the rescan you should extend the partition you want to extend

    growpart /dev/sda 2

    This commands will extend partition 2 on /dev/sda with the amount of free space on the drive, after partition 2.

    After the partition have been extended, you need to extend the filesystem. This can be done by resize2fs

    resize2fs /dev/sda2


    Selfsign with Windows Certification Authority

    If you just create a certificate, and it signed by a Windows Certification Authority, the certs is working just fine in the old Internet Explorer, but Chrome/Firefox and the new Edge browser will failed, with Common Name invalid, the precise error in Chrome is: NET::ERR_CERT_COMMON_NAME_INVALID.

    This is because a normal certificate request, does not included a subject alternative name.
    So to fix this you new to request the certficate, by an inf file instead

    So first create a new Certreq.inf file and paste this into it:

    ;----------------- request.inf -----------------
    [Version]
    
    Signature="$Windows NT$"
    
    [NewRequest]
    
    Subject = "CN=kennethdalbjerg.dk, OU=Hosting, O=KennethDalbjerg, L=DK, S=DK, C=DK" ; replace attribues in this line
    KeySpec = 1
    KeyLength = 2048
    ; Can be 2048, 4096, 8192, or 16384.
    ; Larger key sizes are more secure, but have
    ; a greater impact on performance.
    Exportable = TRUE
    FriendlyName = "Kennethdalbjerg.dk-2024"
    MachineKeySet = TRUE
    SMIME = False
    PrivateKeyArchive = FALSE
    UserProtected = FALSE
    UseExistingKeySet = FALSE
    ProviderName = "Microsoft Strong Cryptographic Provider"
    ProviderType = 12
    RequestType = PKCS10
    KeyUsage = 0xa0
    
    [EnhancedKeyUsageExtension]
    
    OID=1.3.6.1.5.5.7.3.1 ; this is for Server Authentication
    
    [RequestAttributes]
    
    SAN="kennethdalbjerg.dk&dns=www.kennethdalbjerg.dk"
    ;-----------------------------------------------

    Replace kennethdalbjerg.dk and www.kennethdalbjerg.dk, with the name you want. If you don’t want more than one common name, in yours certificate. Then you just in last line remove:
    &dns=www.kennethdalbjerg.dk
    Also replace the name in FriendlyName.

    Now run this command to prepare the CSR file:

    certreq -new certreq.inf certreq.csr

    Copy the certreq.csr to yours Certication Authority server, and the run this command on that server

    certreq -Submit -Attrib "CertificateTemplate:webserver" -Config - c:\certreq.txt

    Replace CertificateTemplate:webserver with the correct name for the template that you want to use.
    Save the certificate by name, i use signcert.cer
    Copy signcert.cert back to the server, that you have generate the CSR file on, and run this command on that server

    certreq -accept signcert.cer
    
    

    Problems in connection to a Webservice from Windows Server 2016 / 2019

    Today, I have this issue, that i could not connect to a webservices, that are hosted by the Danish Tax Service, the URL where: https://emcstest.skat.dk
    I got this warning:

    Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.

    When running these commands

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $WebResponse = Invoke-WebRequest "https://emcstest.skat.dk"

    No matter what I did. But final I tested the webpage against SSLLabs
    https://www.ssllabs.com/ssltest/analyze.html?d=emcstest.skat.dk
    Found these ciphers

    I then run these commands:

    Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    Enable-TlsCipherSuite TLS_AES_256_GCM_SHA384
    Enable-TlsCipherSuite TLS_AES_128_GCM_SHA256
    Enable-TlsCipherSuite TLS_CHACHA20_POLY1305_SHA256
    Enable-TlsCipherSuite TLS_AES_256_GCM_SHA384

    And finally I where able to access the webpage though powershell.

    Problems with FortiClient and no traffic after succesful connection

    I have just help a customer, with a problem with his FortiClient.
    The Forticlient did connect successful, and everything looks good, but there are no traffic iis recieved.

    The OS of the customer where Windows 11.

    The solutions where quite simple, just uninstall this microsoft update: KB2693643
    Read more about the error here: https://community.fortinet.com/t5/FortiClient/Troubleshooting-Tip-VPN-SSL-connected-but-no-IP-address-in/ta-p/248143

    Connect to 365 Exchange mailbox with IMAP and OAuth

    Source: https://stackoverflow.com/questions/73370661/php-connect-mailbox-office-365-with-oauth

    1 – Configure your mail box in Azure

    (I didn’t do this part so i can’t help you more than that ! )

    Edit : Thanks to parampal-poonithis link explains how to configurate in azure.

    You will need :

    • The client Id
    • The tenant Id
    • The secret client
    • The redirect Uri (Set it to http://localhost/test_imap)

    2 – Grab a code to get a token

    Construct this url :

    $TENANT="5-48...";
    $CLIENT_ID="c-9c-....";
    $SCOPE="https://outlook.office365.com/IMAP.AccessAsUser.All";
    $REDIRECT_URI="http://localhost/test_imap";
    
    $authUri = 'https://login.microsoftonline.com/' . $TENANT
               . '/oauth2/v2.0/authorize?client_id=' . $CLIENT_ID
               . '&scope=' . $SCOPE
               . '&redirect_uri=' . urlencode($REDIRECT_URI)
               . '&response_type=code'
               . '&approval_prompt=auto';
    
    echo($authUri);

    Go to the link, connect to the mail box with the passeword. Once it done, you will be redirect to : http://localhost/test_imap?code=LmpxSnTw…&session_state=b5d713….

    Save the code (remove the ‘&’ at the end !) and the session state inside the url. These codes expired after a few hours !

    When you are on this new page look inside the url, you should have htp:/localhost/test_imap?code=MyCodeIShouldSave&session_state=MySessionIShouldSave This is the $CODE and the $SESSION you are looking for for the step 3

    3 – Get an access token

    $CLIENT_ID="c-9c-....";
    $CLIENT_SECRET="Y~tN...";
    $TENANT="5-48...";
    $SCOPE="https://outlook.office365.com/IMAP.AccessAsUser.All offline_access";
    $CODE="LmpxSnTw...";
    $SESSION="b5d713...";
    $REDIRECT_URI="http://localhost/test_imap";
    
    echo "Trying to authenticate the session..";
    
    $url= "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token";
    
    $param_post_curl = [ 
     'client_id'=>$CLIENT_ID,
     'scope'=>$SCOPE,
     'code'=>$CODE,
     'session_state'=>$SESSION,
     'client_secret'=>$CLIENT_SECRET,
     'redirect_uri'=>$REDIRECT_URI,
     'grant_type'=>'authorization_code' ];
    
    $ch=curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($param_post_curl));
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
    
    $oResult=curl_exec($ch);
    
    echo "result : \n";
    
    var_dump($oResult);

    The access_token given in response is going to work only for a few hours. ( If your script is going to be launch on a daily basic you need to recreate a token. I’m going to show you how in the part 5 ! Save the refresh_token inside $oResult. (It are in the middle of the output).
    If you don’t have the “refresh_token” you have forgot to put “offline_access” in the scope)

    4 – Connect to the mail box

    Now choose your favorite library 😉 ! We will use webklex/php-imap for this example (https://github.com/Webklex/php-imap)

    include __DIR__.'/vendor/autoload.php'; 
        
    use Webklex\PHPIMAP\ClientManager;
    
    $access_token="EH.j8s5z8...";
        
    //$cm = new ClientManager($options = ["options" => ["debug" => true]]);                     
    $cm = new ClientManager();                      
    $client = $cm->make([
        'host'          => 'outlook.office365.com',                
        'port'          => 993,
        'encryption'    => 'ssl',
        'validate_cert' => false,
        'username'      => '[email protected]',
        'password'      => $access_token,
        'protocol'      => 'imap',
        'authentication' => "oauth"
    ]);
    
    try {
        //Connect to the IMAP Server
        $client->connect();
        $folder = $client->getFolder('INBOX');
        $all_messages = $folder->query()->all()->get();
        //DONE ! :D     
    } catch (Exception $e) {
        echo 'Exception : ',  $e->getMessage(), "\n";

    5 – Connecting to the mail box everyday

    include __DIR__.'/vendor/autoload.php'; 
        
    use Webklex\PHPIMAP\ClientManager;
    
    $CLIENT_ID="c-9c-....";
    $CLIENT_SECRET="Y~tN...";
    $TENANT="5-48...";
    $REFRESH_TOKEN="EebH9H8S7...";
    
    $url= "https://login.microsoftonline.com/$TENANT/oauth2/v2.0/token";
    
    $param_post_curl = [ 
     'client_id'=>$CLIENT_ID,
     'client_secret'=>$CLIENT_SECRET,
     'refresh_token'=>$REFRESH_TOKEN,
     'grant_type'=>'refresh_token' ];
    
    $ch=curl_init();
    
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POSTFIELDS, http_build_query($param_post_curl));
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
    //ONLY USE CURLOPT_SSL_VERIFYPEER AT FALSE IF YOU ARE IN LOCALHOST !!!
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);// NOT IN LOCALHOST ? ERASE IT !
    
    $oResult=curl_exec($ch);
    
    echo("Trying to get the token.... \n");
    
    if(!empty($oResult)){
        
        echo("Connecting to the mail box... \n");
        
        //The token is a JSON object
        $array_php_resul = json_decode($oResult,true);
        
        if( isset($array_php_resul["access_token"]) ){
    
            $access_token = $array_php_resul["access_token"];
    
            //$cm = new ClientManager($options = ["options" => ["debug" => true]]);                     
            $cm = new ClientManager();                      
            $client = $cm->make([
                'host'          => 'outlook.office365.com',                
                'port'          => 993,
                'encryption'    => 'ssl',
                'validate_cert' => false,
                'username'      => '[email protected]',
                'password'      => $access_token,
                'protocol'      => 'imap',
                'authentication' => "oauth"
            ]);
            
            try {
                //Connect to the IMAP Server
                $client->connect();
            }catch (Exception $e) {
                echo 'Exception : ',  $e->getMessage(), "\n";
            }
    
        }else{
            echo('Error : '.$array_php_resul["error_description"]); 
        }
    }

    It will only connect to the mailbox, you then need to write some more code to get access to the mail. Look at https://github.com/Webklex/php-imap

    Clear mssql cache

    If you for example need to test a query against two SQL servers hardware, its a good idea to clear the cache first.
    This query can do this:

    DBCC DROPCLEANBUFFERS; 
    
    -- Removes all elements from the plan cache.
    
    DBCC FREEPROCCACHE;
    
    -- Displays the number of milliseconds required to parse, compile, and execute each statement.
    
    SET STATISTICS TIME ON; 
    
    -- Display information regarding the amount of disk activity generated by Transact-SQL statements.
    
    SET STATISTICS IO ON;