-
Notifications
You must be signed in to change notification settings - Fork 160
Description
Config API Bug: Cannot Create File-Based Scripts Without Corrupted Database Content
Environment
- Jans Version: 1.15.0
- Installation: Fresh install (December 28, 2025)
- Server: Ubuntu with LDAP backend
- Config API: v1.15.0
Summary
The Config API POST /config/scripts endpoint automatically populates the script field with template code, even when:
- The
scriptfield is not included in the request JSON - The
scriptfield is explicitly set tonullin the request - The
modulePropertiesspecifylocation_type: "file"
This makes it impossible to create truly file-based scripts via the Config API. The template code is corrupted/incomplete Python that causes SyntaxError when Jans tries to load it.
Steps to Reproduce
Step 1: Create file-based script metadata (without script content)
# Get API token
TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
https://yourserver.com/jans-auth/restv1/token \
-d "grant_type=client_credentials&scope=https://jans.io/oauth/config/scripts.write" \
| jq -r '.access_token')
# Create script with NO script field in JSON
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
https://yourserver.com/jans-config-api/api/v1/config/scripts \
-d '{
"name": "test_file_based",
"scriptType": "update_token",
"programmingLanguage": "python",
"moduleProperties": [
{"value1": "location_type", "value2": "file"},
{"value1": "location_path", "value2": "/opt/jans/jetty/jans-auth/custom/scripts/test.py"}
],
"level": 100,
"enabled": false
}'Step 2: Verify script field
# Get created script
curl -s -H "Authorization: Bearer $TOKEN" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/name/test_file_based \
| jq '{name, scriptLength: (.script | length), locationType: (.moduleProperties[] | select(.value1=="location_type") | .value2)}'Expected Result:
{
"name": "test_file_based",
"scriptLength": 0, // or null
"locationType": "file"
}Actual Result:
{
"name": "test_file_based",
"scriptLength": 810, // Template code inserted by API
"locationType": "file"
}Step 3: Check script content
curl -s -H "Authorization: Bearer $TOKEN" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/name/test_file_based \
| jq -r '.script' | head -20Actual Output:
from io.jans.service.cdi.util import CdiUtil
from io.jans.oxauth.security import Identity
from io.jans.model.custom.script.type.authz import ConsentGatheringType
from io.jans.util import StringHelper
import java
import random
class SampleScript(ConsentGatheringType):
def __init__(self, currentTimeMillis):
def init(self, configurationAttributes):
return True
...Issue: This is template/sample code that:
- Is incomplete (missing code in
__init__) - Is for wrong script type (ConsentGatheringType for an update_token script)
- Causes SyntaxError when Jans tries to load it
- Should NOT exist for file-based scripts
Step 4: Try to remove script field via PATCH
# Attempt 1: Set to empty string
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json-patch+json" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/$INUM \
--data '[{"op": "replace", "path": "/script", "value": ""}]'
# Check result
curl -s -H "Authorization: Bearer $TOKEN" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/$INUM \
| jq '{scriptLength: (.script | length)}'Result: scriptLength remains at 810 bytes (not cleared)
# Attempt 2: Set to null
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json-patch+json" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/$INUM \
--data '[{"op": "replace", "path": "/script", "value": null}]'Result: Same - field not cleared
# Attempt 3: Remove field
curl -X PATCH \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json-patch+json" \
https://yourserver.com/jans-config-api/api/v1/config/scripts/$INUM \
--data '[{"op": "remove", "path": "/script"}]'Result: Field persists in database
Expected Behavior
When creating a file-based script:
-
Request JSON includes
modulePropertieswith:[ {"value1": "location_type", "value2": "file"}, {"value1": "location_path", "value2": "/path/to/script.py"} ] -
API should create script metadata with:
scriptfield =nullor emptylocationType= "file" (from moduleProperties)locationPath= specified path
-
Jans should load the Python code from the file path, not from database
Actual Behavior
- API automatically populates
scriptfield with template code - Template code is incomplete/corrupted
- PATCH operations cannot remove the field
- Jans tries to load from database (corrupted template) instead of file
- Results in SyntaxError:
mismatched input 'def' expecting INDENTat line 13
Impact
Critical Impact on File-Based Script Deployment:
- Cannot deploy file-based custom scripts via Config API
- Workaround: Must use Admin UI manually (not automatable)
- Affects CI/CD pipelines and automated deployments
- Makes it impossible to version-control script deployment
Our Use Case:
- Need to deploy 4 custom authentication scripts
- Scripts are 145-572 lines (too large for database field comfortably)
- Want version control on files, not base64 in database
- Config API bug blocks automated deployment
Workaround
Current workaround: Use Admin UI
- Deploy Python files to
/opt/jans/jetty/jans-auth/custom/scripts/ - Manually create script metadata via Admin UI
- Select Location Type = "File"
- Leave Script text area empty
- Specify file path
This works but cannot be automated.
Proposed Fix
Option 1: Don't auto-populate script field when location_type=file
// In script creation logic
if (moduleProperties.contains("location_type", "file")) {
// Don't set default template script
script.setScript(null);
} else {
// Only add template for database-stored scripts
script.setScript(getDefaultTemplate(scriptType));
}Option 2: Make PATCH remove operation actually work
Allow {"op": "remove", "path": "/script"} to set field to null/empty in database.
Option 3: Add POST parameter to skip template
{
"name": "my_script",
"skipTemplate": true,
"moduleProperties": [...]
}Additional Context
Tested on:
- Fresh Jans 1.15.0 installation
- Multiple script types (update_token, person_authentication)
- Both POST new script and PATCH existing script operations
Logs showing corruption:
ERROR [io.jans.service.PythonService] - Failed to load python file
SyntaxError: mismatched input 'def' expecting INDENT (meus_update_token.py, line 13)
Script field content inspection:
The auto-generated template is 810 bytes of incomplete Python code with wrong imports for the script type.
Questions
- Is the template auto-population intentional for file-based scripts?
- If yes, why can't it be removed via PATCH?
- Is there a documented way to create file-based scripts via API without script field corruption?
- Should file-based scripts (
locationType=file) take precedence over databasescriptfield?
Request
Please either:
- Fix Config API to not auto-populate script field when
locationType=file, OR - Document the correct API procedure for file-based script creation, OR
- Fix PATCH to allow removing the script field
Thank you!