WebLogic Identity Asserter
The Maverics Identity Asserter is a custom WebLogic identity asserter module. This module validates that a request comes from a legitimate third-party authentication proxy, reads in a users’ identity from the request header, and returns either a distinguished name (DN) or a short name which WebLogic will use to build its identity context.
Server requirements
- Oracle WebLogic 12c
- Java 8
Install
To install the identity asserter, copy it to the $WL_HOME/server/lib/mbeantypes
directory ($WL_HOME
is the home directory of the WebLogic server).
- Under the target domain, select “Security Realms”.
- Select the target realm, e.g. “myrealm”, and then select “Providers” -> “Authentication”.
- Create a new Authentication Provider of type “MavericsIdentityAsserter”.
- Once created, re-order the security modules by moving the newly created asserter to the beginning of the list.
- Configure the flag as
SUFFICIENT
for Strata Identity Asserter. - Generate the base64 encoded signature verification key as outlined in the example below.
- Select the “Provider Specific” tab and add the base64 encoded key you created.
- Configure the flag for all other security modules as
SUFFICIENT
. - Restart the WebLogic server.
- Test the functionality by accessing the URL.
Upgrade
To upgrade the identity asserter, replace the existing Maverics Identity Asserter in
the $WL_HOME/server/lib/mbeantypes
directory with a new version. After replacing the
JAR, restart the WebLogic server.
Example
This example demonstrates how the Orchestrator can be used to authenticate a user and
proxy traffic to WebLogic. Once a request is received by WebLogic, the identity
asserter will validate the MAVERICS_USERNAME
header value and build the identity
context.
In order to generate a private key that will be used to sign JWTs, the following
command can be run. This example stores the generated private key in a secret store
with a name of webLogicPrivateKey
.
openssl genrsa -out wl-private-key.pem 2048
After a private key has been generated, the public key used for verifying the signature can be extracted with the following command.
openssl rsa -in wl-private-key.pem -outform PEM -pubout -out wl-public-key.pem
After the public key has been extracted, base64 encode it before adding it as a property in WebLogic. Base64 encoding the key is a requirement since WebLogic does not permit multi-line properties.
openssl base64 -A -in wl-public-key.pem
Now that the key pair has been generated and the necessary properties have been added to WebLogic, the below Maverics config file can be used as a reference for how to pass a JWT header value to WebLogic.
apps:
- name: exampleWebLogic
type: proxy
routePatterns:
- /
upstream: https://app-internal.example.com
headers:
- createHeaderSE:
funcName: CreateHeader
file: /etc/maverics/webLogic-createHeader.go
metadata:
# userLookupKey is the key that will be used to look up the user's
# username from the session store. The corresponding value will be passed
# as the 'sub' claim in the JWT.
userLookupKey: azure.name
# privateKeyLookupKey is the key that will be used to retrieve the
# signing key from the secret store.
privateKeyLookupKey: webLogicPrivateKey
# jwtLifetime is the lifetime of the JWT in hours. The value should be
# set to match the lifetime of a user's session.
jwtLifetime: 24
policies:
- location: /
authentication:
idps:
- azure
authorization:
allowAll: true
/etc/maverics/webLogic-createHeader.go
package main
import (
"errors"
"fmt"
"net/http"
"time"
"github.com/strata-io/service-extension/orchestrator"
"github.com/strata-io/service-extension/weblogic"
)
// CreateHeader creates an HTTP header that will be consumed and validated by
// the WebLogic Identity Asserter. The header has a name of 'MAVERICS_USERNAME' and
// a signed JWT as the value.
func CreateHeader(
api orchestrator.Orchestrator,
_ http.ResponseWriter,
_ *http.Request,
) (http.Header, error) {
logger := api.Logger()
logger.Debug("se", "creating header for WebLogic")
metadata := api.Metadata()
userLookupKey, _ := metadata["userLookupKey"].(string)
privateKeyLookupKey, _ := metadata["privateKeyLookupKey"].(string)
jwtLifetime, _ := metadata["jwtLifetime"].(int)
session, err := api.Session()
if err != nil {
return nil, fmt.Errorf("failed to get session: %w", err)
}
name, err := session.GetString(userLookupKey)
if err != nil {
return nil, fmt.Errorf("failed to retrieve username from session: %w", err)
}
secretProvider, err := api.SecretProvider()
if err != nil {
return nil, fmt.Errorf("failed to retrieve secret provider: %w", err)
}
privateKey := secretProvider.GetString(privateKeyLookupKey)
if len(privateKey) == 0 {
return nil, errors.New("private key not found in secret provider")
}
jwt, err := api.WebLogic().NewSignedJWT(weblogic.Config{
RSAPrivateKeyPEM: privateKey,
Subject: name,
Lifetime: time.Duration(jwtLifetime) * time.Hour,
})
if err != nil {
return nil, fmt.Errorf("failed to construct JWT: %w", err)
}
header := make(http.Header)
header["MAVERICS_USERNAME"] = []string{jwt}
return header, nil
}