Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

j_security_check returns 200 whatever the password is

25 views
Skip to first unread message

Xavier Humbert

unread,
Dec 3, 2024, 9:58:36 AM12/3/24
to rundeck-discuss
Hi,

I'm facing a strange issue : this code returns a status code 200,
regardless of the password submitted :

import sys
import requests
def connect(instance, username, password):
    s = requests.Session()
    r = s.post(instance +"/j_security_check", data={ "j_username":
username, "j_password": password })
    if (r.status_code != 200):
        print("CRITICAL - Cannot connect to {}" . format (instance))
        sys.exit (2)
    return s

This Rundeck 5.7.0 RPM install on RHEL9

Regards,

Xavier

--
Xavier Humbert
CRT Supervision et Exploitation de Niveau 1
Direction des Services d'Information du Grand Est
Rectorat de l'Académie de Nancy-Metz
Ministère de l'Éducation Nationale et de la Jeunesse
03 83 86 27 39

Xavier Humbert

unread,
Dec 3, 2024, 10:24:36 AM12/3/24
to rundeck...@googlegroups.com
Same behaviour with curl :

[xavier@imladris ~]$ curl -sIL -u rundeck-sup:${newPass}
https://ordo.tldr/prmutu02/j_security_check | grep HTTP/1.1
HTTP/1.1 302 Found
HTTP/1.1 200 OK
# -------------------------------------------------------------------------
[xavier@imladris ~]$ curl -sIL -u rundeck-sup:${OldPass}
https://ordo.tldr/prmutu02/j_security_check | grep HTTP/1
HTTP/1.1 302 Found
HTTP/1.1 200 OK
# -------------------------------------------------------------------------
[xavier@imladris ~]$ curl -sIL -u
rundeck-sup:TotallyWrongAndRandomPassword42
https://ordo.tldr/prmutu02/j_security_check | grep HTTP/1.1
HTTP/1.1 302 Found
HTTP/1.1 200 OK
# -------------------------------------------------------------------------
[xavier@imladris ~]$ curl -sIL -u rundeck-sup:
https://ordo.tldr/prmutu02/j_security_check | grep HTTP/1.1
HTTP/1.1 302 Found
HTTP/1.1 200 OK

rac...@rundeck.com

unread,
Dec 3, 2024, 4:20:46 PM12/3/24
to rundeck-discuss

Hi Xavier,

I found something interesting about Rundeck API design, I tried this basic code on Python 3:

import requests s = requests.Session() r = s.post("http://localhost:4440/j_security_check", data={"j_username": "admin", "j_password": "admin1"}) r.status_code r.url print ("####### j_security_check endpoint:") print(r) print ("") r = s.get("http://localhost:4440/api/50/projects",headers = {'Accept': 'application/json'}) print ("####### listing projects endpoint:") print(r)

As you see this creates a session based on the j_security_check data and then with this session tries to execute actions against the Rundeck API.

With the correct credentials:

####### j_security_check endpoint: <Response [200]> ####### listing projects endpoint: <Response [200]>

With the incorrect credentials:

####### j_security_check endpoint: <Response [200]> ####### listing projects endpoint: <Response [403]>

So, the first endpoint always is listening while the instance is running and returns 200 even with the wrong credentials, that is explained here. But with the session created, at the moment of requesting a specific action, the action is rejected because the credentials stored in the session are wrong.

So, if you call any “real action” against the API using the j_security_check method via CURL, you will get the expected responses. I tried in this “too-basic” form (against the system info endpoint):

curl -v -c cookie -b cookie -d j_username=admin -d j_password=admin http://localhost:4440/j_security_check -H "Accept: application/json" http://localhost:4440/api/50/system/info/

With the correct user/password:

* WARNING: failed to open cookie file "cookie" * Host localhost:4440 was resolved. * IPv6: ::1 * IPv4: 127.0.0.1 * Trying 127.0.0.1:4440... * Connected to localhost (127.0.0.1) port 4440 * using HTTP/1.x > POST /j_security_check HTTP/1.1 > Host: localhost:4440 > User-Agent: curl/8.11.0 > Accept: application/json > Content-Length: 33 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 33 bytes < HTTP/1.1 302 Found < Date: Tue, 03 Dec 2024 20:00:55 GMT < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers * Added cookie JSESSIONID="node0cavqruhrkpqu1gyfzhgbifij022.node0" for domain localhost, path /, expire 0 < Set-Cookie: JSESSIONID=node0cavqruhrkpqu1gyfzhgbifij022.node0; Path=/; HttpOnly; SameSite=Lax < Expires: Thu, 01 Jan 1970 00:00:00 GMT < Location: http://localhost:4440/ < Content-Length: 0 < * Connection #0 to host localhost left intact * Re-using existing connection with host localhost > POST /api/50/system/info/ HTTP/1.1 > Host: localhost:4440 > User-Agent: curl/8.11.0 > Cookie: JSESSIONID=node0cavqruhrkpqu1gyfzhgbifij022.node0 > Accept: application/json > Content-Length: 33 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 33 bytes < HTTP/1.1 200 OK < Date: Tue, 03 Dec 2024 20:00:55 GMT < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers < Referrer-Policy: strict-origin-when-cross-origin < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: Thu, 01 Jan 1970 00:00:00 GMT < X-Frame-Options: deny < Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=() < X-XSS-Protection: 0 < X-Content-Type-Options: nosniff < Content-Security-Policy: default-src 'none' ; script-src 'self' https://content.analytics.rundeck.com 'unsafe-inline' 'unsafe-eval' ; style-src 'self' 'unsafe-inline' ; img-src * data: ; font-src 'self' data: ; connect-src 'self' https://api.rundeck.com https://data.analytics.rundeck.com ; form-action 'self' ; < Strict-Transport-Security: max-age=31536000; includeSubDomains * Replaced cookie JSESSIONID="node0vdg2yblph3b31d7am6e1c38ku23.node0" for domain localhost, path /, expire 0 < Set-Cookie: JSESSIONID=node0vdg2yblph3b31d7am6e1c38ku23.node0; Path=/; HttpOnly; SameSite=Lax < Content-Type: application/json;charset=utf-8 < Transfer-Encoding: chunked < {"system":{"executions":{"active":"true","executionMode":"active"},"extended":null,"healthcheck":{"contentType":"application/json","href":"http://localhost:4440/api/50/metrics/healthcheck"},"jvm":{"implementationVersion":"11.0.25+9","name":"OpenJDK 64-Bit Server VM","vendor":"AlienBOB Slackware","version":"11.0.25"},"metrics":{"contentType":"application/json","href":"http://localhost:4440/api/50/metrics/metrics?pretty=true"},"os":{"arch":"amd64","name":"Linux","version":"6.11.10"},"ping":{"contentType":"text/plain","href":"http://localhost:4440/api/50/metrics/ping"},"rundeck":{"apiversion":"50","base":"/home/reideianto/Programs/rundeck/5.7.0","build":"5.7.0-20241021","buildGit":"v5.7.0-0-g1763aa0","node":"localhost","serverUUID":"0a4a4f42-3d40-49c5-8c59-b1272b250905","version":"5.7.0-20241021"},"stats":{"cpu":{"loadAverage":{"average":0,"unit":"percent"},"processors":16},"memory":{"free":602334208,"max":4294967296,"total":1110441984,"unit":"byte"},"scheduler":{"running":0,"threadPoolSize":10},"threads":{"acti* Connection #0 to host localhost left intact ve":41},"uptime":{"duration":2798720,"since":{"datetime":"2024-12-03T19:14:16Z","epoch":1733253256691,"unit":"ms"},"unit":"ms"}},"threadDump":{"contentType":"text/plain","href":"http://localhost:4440/api/50/metrics/threads"},"timestamp":{"datetime":"2024-12-03T20:00:55Z","epoch":1733256055411,"unit":"ms"}}}

Returns 200 as expected. Now, with the incorrect credentials:

* Host localhost:4440 was resolved. * IPv6: ::1 * IPv4: 127.0.0.1 * Trying 127.0.0.1:4440... * Connected to localhost (127.0.0.1) port 4440 * using HTTP/1.x > POST /j_security_check HTTP/1.1 > Host: localhost:4440 > User-Agent: curl/8.11.0 > Cookie: JSESSIONID=node01592f3nz3mnie1o5jkzm1w134y14.node0 > Accept: application/json > Content-Length: 34 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 34 bytes < HTTP/1.1 302 Found < Date: Tue, 03 Dec 2024 19:57:16 GMT < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers * Added cookie grails_remember_me="" for domain localhost, path /, expire 1 < Set-Cookie: grails_remember_me=; Path=/; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0 < Expires: Thu, 01 Jan 1970 00:00:00 GMT < Location: http://localhost:4440/user/error < Content-Length: 0 < * Connection #0 to host localhost left intact * Re-using existing connection with host localhost > POST /api/50/system/info/ HTTP/1.1 > Host: localhost:4440 > User-Agent: curl/8.11.0 > Cookie: JSESSIONID=node01592f3nz3mnie1o5jkzm1w134y14.node0 > Accept: application/json > Content-Length: 34 > Content-Type: application/x-www-form-urlencoded > * upload completely sent off: 34 bytes < HTTP/1.1 403 Forbidden < Date: Tue, 03 Dec 2024 19:57:16 GMT < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers < Referrer-Policy: strict-origin-when-cross-origin < Cache-Control: no-cache, no-store, max-age=0, must-revalidate < Pragma: no-cache < Expires: 0 < X-Frame-Options: deny < Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=() < X-XSS-Protection: 0 < X-Content-Type-Options: nosniff < Content-Security-Policy: default-src 'none' ; script-src 'self' https://content.analytics.rundeck.com 'unsafe-inline' 'unsafe-eval' ; style-src 'self' 'unsafe-inline' ; img-src * data: ; font-src 'self' data: ; connect-src 'self' https://api.rundeck.com https://data.analytics.rundeck.com ; form-action 'self' ; < Strict-Transport-Security: max-age=31536000; includeSubDomains < Content-Type: application/json;charset=utf-8 < Content-Length: 131 < * Connection #0 to host localhost left intact {"error":true,"apiversion":50,"errorCode":"unauthorized","message":"(unauthenticated) is not authorized for: /api/50/system/info/"}

Returns 403 as expected.

Hope it helps!

Reply all
Reply to author
Forward
0 new messages