Category: Technology

Authenticating WebLogic Admin Console with SAML 2.0 and PingID

Log into your console. Navigate to “Security Realms” and click on your admin console’s realm – here “myrealm”

A screenshot of a computer

AI-generated content may be incorrect.

From the first row of tabs, select “Providers”. On the second row of tabs, ensure you are on “Authentication”. Click “New” to create a new identity asserter.

A screenshot of a computer

AI-generated content may be incorrect.

Provide a name – here, it is called SAML_IA – and ensure the type is “SAML2IdentityAsserter”

A screenshot of a computer

AI-generated content may be incorrect.

Click OK to create the item. Then click the “New” button again to create a new SAML Authenticator

A screenshot of a computer

AI-generated content may be incorrect.

Restart the WebLogic server, then navigate to “Environment” => “Servers” and select the AdminServer

A screenshot of a computer

AI-generated content may be incorrect.

On the first row of tabs, select “Configuration”, on the second row of tabs, select “Federation Servies”, and on the third row of tabs select “SAML 2.0 General”

The published site URL will be your WebLogic host base followed by /saml2

Provide a unique entity ID that needs to match up with what we configure in PingID. Here, I used “LJRWebLogic”

A screenshot of a computer

AI-generated content may be incorrect.

Save the changes and then use the “Publish Metadata” button to save a metadata file that I will use with PingID. You will be saving an XML file

A close up of a text

AI-generated content may be incorrect.

Now select the “SAML 2.0 Service Provider” tab on the third row of tabs. Click “Enabled” to enable the service provider. POST binding should be enabled, but we do not need Artifact binding enabled. Click “Save” to save the changes.

A screenshot of a computer

AI-generated content may be incorrect.

Navigate back to “Security Realms” and select your realm. On the first row of tabs, select “Providers”; on the second row of tabs, select “Authentication”. Click the hyperlink for “SAML_IA”

A screenshot of a computer

AI-generated content may be incorrect.

Click the “Management” tab

A screenshot of a computer

AI-generated content may be incorrect.

You will be provided a metadata file from PingID. Place that somewhere on your server (I used /tmp). Click “New” and then select “New Web Single Sign-On Identity Provider Partner”

A screenshot of a computer

AI-generated content may be incorrect.

Navigate to the metadata file and select it. Provide a name for the identity provider – here, I used PingID. Cilck “OK” to import the PingID details.

A screenshot of a computer

AI-generated content may be incorrect.

Click on the new entry to configure it

A screenshot of a computer

AI-generated content may be incorrect.

Click “Enabled” to enable the Identity Provider. The redirect URIs should be /console/*

A screenshot of a computer

AI-generated content may be incorrect.

Finally, on the WebLogic Server Admin Console, navigate to the domain name -> [Configuration] -> [General] and expand the [Advanced] link

Update cookie name in WLS admin console to be JSESSIONID.

A screenshot of a computer

AI-generated content may be incorrect.

Save the changes and restart the WebLogic server. Navigating to the console, here https://docker.rushworth.us:7001/console, will direct the user to PingID for authentication and then redirect the user’s browser back to the WebLogic server. Looking in the upper right corner of the screen, they will see they are logged in with their directory ID.

A close-up of a computer code

AI-generated content may be incorrect.

Note: You can still access the local authentication dialog by navigating directly to console/login/LoginForm.jsp – e.g. http://docker.rushworth.us:7001/console/login/LoginForm.jsp — but the “normal” URL will redirect users to PingID

Note Also: There needs to be some step here to map PingID users to a role in WebLogic

Failing to do so, you will complete the PingID authentication but be denied access to the WebLogic Admin Console:

A white box with black text

AI-generated content may be incorrect.

 

Enabling SSL on the WebLogic Server Administration Console

Prior to enabling SAML authentication, please ensure your WebLogic Admin Console is using SSL. You will need a JKS keystore with your public/private key pair.

If you have a base64 encoded public/private key pair, create a JKS file as follows:

openssl pkcs12 -export -out docker.p12 -inkey docker.rushworth.us.key -in docker.rushworth.us.cer -name docker_rushworth_us -password pass:IChangedIt

keytool -importkeystore -srckeystore docker.p12 -srcstoretype PKCS12 -destkeystore docker.jks -deststoretype JKS -deststorepass IChangedIt -srcstorepass IChangedIt

List the keystore contents to confirm your certificate is present using:

keytool -list -keystore docker.jks -storepass IChangedIt

A black rectangular frame with white text AI-generated content may be incorrect.

The certificate’s alias will be needed to configure SSL on the console. In this example, my certificate’s alias is docker_rushworth_us

Once there is a JKS file with your keypair located on the server, configure WebLogic to use it. On the WebLogic Admin Console, navigate to [domain]->Environment->Servers and select the system you want to configure. Here, AdminServer(admin)

A screenshot of a computer AI-generated content may be incorrect.

On the “Configuration” tab, select the “General” sub-tab. Check the box for “SSL Listen Port Enabled” and supply a port number.

A screenshot of a computer AI-generated content may be incorrect.

On the Keystores sub-tab, click “Change” to change the keystore being used.

A screenshot of a computer AI-generated content may be incorrect.

Select “Custom Identity and Java Standard Trust”. Enter the path to your JKS file. The keystore type is jks. Enter and confirm the password you used to create the keystore. Enter the password for the cacerts file (java default is changeit)

A screenshot of a computer AI-generated content may be incorrect.

On the SSL sub-tab, input the alias of the certificate. Also enter and confirm the key passphrase.

A screenshot of a computer AI-generated content may be incorrect.

 

KRDP Fails to Start

Scott has been trying to set up KRDP recently, and continued to get a lot of strange errors attempting to start the server. Through the GUI, it would fall over. From the command line, it output a lot of text. But they all seemed to indicate something couldn’t load. The log file had shared libraries (although ldd said all dependencies were met). The command line said things were found but could not run.

Had him run netstat to see if something else was bound to the port … and it was, but instead of printing the pid and binary name, it said off … which was a new one to me. Fortunately, lsof didshow us what was listening on the port. Stopped xrdp and, voila, krdp starts and runs.

[lisa@fedora01 ~/]# netstat -nap | grep 3389
tcp 0 0 0.0.0.0:3389 0.0.0.0:* LISTEN off...

[lisa@fedora01 ~/]# lsof -i TCP:3389
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
xrdp 1855 root 13u IPv4 39470 0t0 TCP *:ms-wbt-server (LISTEN)

In retrospect, it does tell you what the problem is. ‘Unable to listen for connections on QHostAddress(“”) 0’ means “unable to bind to ip:port

Jan 29 06:49:14 fedora01 systemd[10239]: Started plasma-krdp_server.service - KRDP Server.
Jan 29 06:49:16 fedora01 krdpserver[11054]: libEGL warning: egl: failed to create dri2 screen
Jan 29 06:49:16 fedora01 krdpserver[11054]: libEGL warning: egl: failed to create dri2 screen
Jan 29 06:49:17 fedora01 krdpserver[11054]: org.kde.krdp: Unable to listen for connections on QHostAddress("") 0
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "/org/freedesktop/portal/desktop" interface "org.freedesktop.portal.Re moteDesktop" member "NotifyKeyboardKeycode": Marshalling failed: Invalid object path passed in arguments
Jan 29 06:49:17 fedora01 krdpserver[11054]: qt.dbus.integration: QDBusConnection: error: could not send message to service "org.freedesktop.portal.Desktop" path "" interface "org.freedesktop.portal.Session" member "Close": Object p ath cannot be empty
Jan 29 06:49:17 fedora01 systemd[10239]: plasma-krdp_server.service: Main process exited, code=exited, status=255/EXCEPTION
Jan 29 06:49:17 fedora01 systemd[10239]: plasma-krdp_server.service: Failed with result 'exit-code'.

adsaf

Chocolate Chip Cookies with Dark Cherries and Almond Flour

Anya made me birthday cookies! I wanted to save the recipe because they turned out really well.

 
Ingredients:
  • 1 3/4 cups all-purpose flour
  • 1/2 cup almond flour
  • 1 teaspoon baking soda
  • 1/2 teaspoon salt
  • 1 cup unsalted butter, softened
  • 1 cup maple syrup
  • 1/2 cup plain Greek yogurt
  • 2 large eggs
  • 2 cups semi-sweet chocolate chips
  • 1 cup frozen dark cherries, roughly chopped
Instructions:
  1. Preheat your oven to 375°F. Line baking sheets with parchment paper.
  2. In a medium bowl, whisk together the all-purpose flour, almond flour, baking soda, and salt. Set aside.
  3. In a large mixing bowl, beat the softened butter with the maple syrup until well mixed. The mixture will be looser than a typical creamed butter-sugar mixture due to the syrup.
  4. Mix in the Greek yogurt until smooth. Beat in the eggs one at a time, mixing well after each addition.
  5. Gradually add the dry ingredients to the wet ingredients, mixing until just combined. The dough will be a bit softer due to the syrup and yogurt.
  6. Gently fold in the chocolate chips and frozen dark cherries until evenly distributed throughout the dough.
  7. Drop rounded tablespoons of dough onto the prepared baking sheets, leaving about 2 inches between each cookie to allow for spreading.
  8. Bake the cookies in the preheated oven for 10-12 minutes, or until the edges are golden brown and the centers are set but still soft. If you made really big cookies, this may be more like 20 minutes!
  9. Allow the cookies to cool on the baking sheet for about 5 minutes before transferring them to a wire rack to cool completely.

Kubernetes: Renewing Client Admin Cert

When the certificate for a k8s manager account has expired, create a new key request for the same CN and sign it against the k8s CA:

#!/bin/bash
# Run this from the K8s controller where the platform's CA keys are located
cd ~/kubectl_cert/

# Get the current year
current_year=$(date +%Y)

# Generate private key
openssl genpkey -algorithm RSA -out kubectl-${current_year}-k8admin-key.pem

# Generate CSR
openssl req -new -key kubectl-${current_year}-k8admin-key.pem -out kubectl-${current_year}-k8admin.csr -subj "/O=system:masters/CN=kubernetes-admin"

# Sign the CSR to create a certificate
openssl x509 -req -in kubectl-${current_year}-k8admin.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out kubectl-${current_year}-k8admin-cert.pem -days 365 -extensions v3_req

# Check expiry is in future
openssl x509 -in kubectl-${current_year}-k8admin-cert.pem -noout -enddate

# Update kubeconfig with new credentials
kubectl config set-credentials kubernetes-admin --client-certificate=~/kubectl_cert/kubectl-${current_year}-k8admin-cert.pem --client-key=~/kubectl_cert/kubectl-${current_year}-k8admin-key.pem

Finding Active Directory Global Catalog Servers

… or domain controllers, or kerberos, or …

Back when I managed the Active Directory environment, I’d have developers ask where they should direct traffic. Now, since it was all LDAP, I did the right thing and got a load balanced virtual IP built out so they had “ad.example.com” on port 636 & all of my DCs had SAN’s on their SSL certs so ad.example.com was valid. But! It’s not always that easy — especially if you are looking for something like the global catalog servers. Or no such VIP exists. Luckily, the fact people are logging into the domain tells you that you can ask the internal DNS servers to give you all of this good info. Because domain controllers register service records in DNS.

These are the registrations for all servers regardless of associated site.

_ldap: The LDAP service record is used for locating domain controllers that provide directory services over LDAP.
_ldap._tcp.example.com

_kerberos: This record is used for locating domain controllers that provide Kerberos authentication services.
_kerberos._tcp.example.com

_kpasswd: The kpasswd service record is used for finding domain controllers that can handle Kerberos principal password changes.
_kpasswd._tcp.example.com

_gc: The Global Catalog service record is used for locating domain controllers that have the Global Catalog role.
_gc._tcp._tcp.example.com

_ldap._tcp.pdc: If you need to identify which domain controller holds the PDC emulator operations master role.
_ldap._tcp.pdc._msdcs.example.com

You can also find global catalog, Kerberos, and LDAP service records registered in individual sites. For all servers specific to a site, you need to use _tcp.SiteName._sites.example.com instead.

Example — return all GC’s specific to the site named “SiteXYZ”:
dig _gc._tcp.SiteXYZ._sites.example.com SRV

If you are using Windows, first enter “set type=SRV” to return service records and then query for the specific service record you want to view:

C:\Users\lisa>nslookup
Default Server: dns123.example.com
Address: 10.237.123.123

> set type=SRV
> _gc._tcp.SiteXYZ._sites.example.com
Server:  dns123.example.com
Address:  10.23.123.123

_gc._tcp.SiteXYZ._sites.example.com SRV service location:
          priority       = 0
          weight         = 100
          port           = 3268
          svr hostname   = addc032.example.com

Microsoft Word – Custom Table of Contents to Omit Heading 1

I know I could sort this by adjusting which “style” I use when I write documents … but I like Heading 1 as the title, Heading 2 as a paragraph title, etc. To create a table of contents below the title line that doesn’t start with the title line and then have everything subordinate to that top item, create a custom table of contents:

Select “Options”

And simply re-map the styles to TOC levels – Heading 1 doesn’t get a level. Heading 2 becomes 1, Heading 3 becomes 2, and Heading 4 becomes 3.

Voila – now I’ve got a bunch of “top level” items from Heading 2

 

Sumo Logic: Creating Roles via API

This script creates very basic roles with no extra capabilities and restricts the role to viewing only the indicated source category’s data.

################################################################################
# This script reads an Excel file containing role data, then uses the Sumo Logic
# API to create roles based on the data. It checks each row for a role name and
# uses the source category to set data filters. The script requires a config.py
# file with access credentials.
################################################################################
import pandas as pd
import requests
import json
from config import access_id, access_key  # Import credentials from config.py

# Path to Excel file
excel_file_path = 'NewRoles.xlsx'

# Base URL for Sumo Logic API
base_url = 'https://api.sumologic.com/api/v1'

################################################################################
# Function to create a new role using the Sumo Logic API.
# 
# Args:
#     role_name (str): The name of the role to create.
#     role_description (str): The description of the role.
#     source_category (str): The source category to restrict the role to.
# 
# Returns:
#     None. Prints the status of the API call.
################################################################################
def create_role(role_name, role_description, source_category):
    
    url = f'{base_url}/roles'

    # Role payload
    data_filter = f'_sourceCategory={source_category}'
    payload = {
        'name': role_name,
        'description': role_description,
        'logAnalyticsDataFilter': data_filter,
        'auditDataFilter': data_filter,
        'securityDataFilter': data_filter
    }

    # Headers for the request
    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    # Debugging line
    print(f"Attempting to create role: '{role_name}' with description: '{role_description}' and filter: '{data_filter}'")

    # Make the POST request to create a new role
    response = requests.post(url, auth=(access_id, access_key), headers=headers, data=json.dumps(payload))

    # Check the response
    if response.status_code == 201:
        print(f'Role {role_name} created successfully.')
    else:
        print(f'Failed to create role {role_name}. Status Code: {response.status_code}')
        print('Response:', response.json())

################################################################################
# Reads an Excel file and processes each row to extract role information and
# create roles using the Sumo Logic API.
# 
# Args:
#     file_path (str): The path to the Excel file containing role data.
# 
# Returns:
#     None. Processes the file and attempts to create roles based on the data.
################################################################################
def process_excel(file_path):
    # Load the spreadsheet
    df = pd.read_excel(file_path, engine='openpyxl')

    # Print column names to help debug and find correct ones
    print("Columns found in Excel:", df.columns)

    # Iterate over each row in the DataFrame
    for index, row in df.iterrows():
        role_name = row['Role Name']  # Correct column name for role name
        source_category = row['Source Category']  # Correct column name for source category to which role is restricted

        # Only create a role if the role name is not null
        if pd.notnull(role_name):
            role_description = f'Provides access to source category {source_category}'
            create_role(role_name, role_description, source_category)


# Process the Excel file
process_excel(excel_file_path)