I'm attempting to use OAuth with the optional service HTTP header
(X-service or service) using the "client_credentials" grant type with CAS
v6.0.
I have three simple services registered:
HTTP-100.json
{
"@class" : "org.apereo.cas.services.RegexRegisteredService",
"serviceId" : "^(http|https)://.*",
"name" : "HTTP",
"id" : 100,
"description" : "This service definition authorizes all application urls
that support HTTP or HTTPS protocols.",
"evaluationOrder" : 10000
}
OAUTH_CLIENT-101.json
{
"@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
"clientId": "scdb_api_v1",
"clientSecret": "clientSecret11",
"name" : "OAUTH_CLIENT",
"id" : 101,
"serviceId" : "http://example.com/api/v1",
"supportedGrantTypes": [ "java.util.HashSet", [ "client_credentials" ] ],
"jsonFormat":true
}
OAUTH_CLIENT-102.json
{
"@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
"clientId": "scdb_api_v2",
"clientSecret": "clientSecret22",
"name" : "OAUTH_CLIENT",
"id" : 102,
"serviceId" : "http://example.com/api/v2",
"supportedGrantTypes": [ "java.util.HashSet", [ "client_credentials" ] ],
"jsonFormat":true
}
According to the documentation
<https://apereo.github.io/cas/6.0.x/installation/OAuth-OpenId-Authentication.html>:
"You may optionally also pass along a service or X-service header value
that identifies the target application url. The header value must match the
OAuth service definition in the registry that is linked to the client id."
When I execute the attached Python script I get results which do not
enforce that the X-service header match the defined serviceId, instead it
seems it simply must match ANY serviceId.
# TEST 1
Request access token for "X-service: http://example.com/api/v1", with
credentials for API v1
Response status code: 200, data: {"access_token":
"AT-16-Yz-0nTnaoeDQLMledeZByMHht1T6cL-L","token_type":"bearer","expires_in":
28800,"scope":[]}
Request profile for token: AT-16-Yz-0nTnaoeDQLMledeZByMHht1T6cL-L
Response status code: 200: data: {"service":"http://example.com/api/v1",
"attributes":{},"id":"scdb_api_v1","client_id":"scdb_api_v1"}
# TEST 2
Request access token for "X-service: http://example.com/api/v2", but with
credentials for API v1
Response status code: 200, data: {"access_token":
"AT-17-PWxfLaWN4P1mxf5fKG3qamCSfxJEclsC","token_type":"bearer","expires_in":
28800,"scope":[]}
Request profile for token: AT-17-PWxfLaWN4P1mxf5fKG3qamCSfxJEclsC
Response status code: 200, data: {"service":"http://example.com/api/v2",
"attributes":{},"id":"scdb_api_v1","client_id":"scdb_api_v2"}
# TEST 3
Request access token for "X-service: http://example.com/api/v3", but with
credentials for API v1
Response status code: 200, data: {"access_token":
"AT-18-pba2h3sGLPfoVRw-HEqveQ-tplPBk9De","token_type":"bearer","expires_in":
28800,"scope":[]}
Request profile for token: AT-18-pba2h3sGLPfoVRw-HEqveQ-tplPBk9De
Response status code: 200, data: {"attributes":{},"id":"scdb_api_v1"}
As the results demonstrate I can use the credentials for one service to
authenticate for another service!
Perhaps I have misunderstood how the X-service header is meant to be used,
or how services are resolved.
But my expectation was that only TEST 1 would be able to successfully
authenticate.
Any insight into this matter would be greatly appreciated.
Thanks,
-Dylan
--
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
---
You received this message because you are subscribed to the Google Groups "CAS
Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/a/apereo.org/d/msgid/cas-user/a5bb8079-ada5-46df-a0b5-64e480311fdd%40apereo.org.
#!/usr/bin/env python3
#
# Example usage of CAS OAuth 2.0 for authentication.
#
import sys
import json
import uuid
from datetime import date
from pprint import pprint
from getpass import getpass
import requests
CAS_BASE_URL = 'https://10.0.8.194:8443/cas'
# HTTP-100.json
# {
# "@class" : "org.apereo.cas.services.RegexRegisteredService",
# "serviceId" : "^(http|https)://.*",
# "name" : "HTTP",
# "id" : 100,
# "description" : "This service definition authorizes all application urls that support HTTP or HTTPS protocols.",
# "evaluationOrder" : 10000
# }
# OAUTH_CLIENT-101.json
# {
# "@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
# "clientId": "scdb_api_v1",
# "clientSecret": "clientSecret11",
# "name" : "OAUTH_CLIENT",
# "id" : 101,
# "serviceId" : "http://example.com/api/v1",
# "supportedGrantTypes": [ "java.util.HashSet", [ "client_credentials" ] ],
# "jsonFormat":true
# }
# OAUTH_CLIENT-102
# {
# "@class" : "org.apereo.cas.support.oauth.services.OAuthRegisteredService",
# "clientId": "scdb_api_v2",
# "clientSecret": "clientSecret22",
# "name" : "OAUTH_CLIENT",
# "id" : 102,
# "serviceId" : "http://example.com/api/v2",
# "supportedGrantTypes": [ "java.util.HashSet", [ "client_credentials" ] ],
# "jsonFormat":true
# }
# Test #1
print('Request access token for "X-service: http://example.com/api/v1", with credentials for API v1')
res = requests.post(CAS_BASE_URL + '/oauth2.0/accessToken', verify=False,
headers={
'Accept':'application/json',
'X-service': 'http://example.com/api/v1'
},
data={
'grant_type':'client_credentials',
'client_id':'scdb_api_v1',
'client_secret': 'clientSecret11',
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)
data = res.json()
print('Request profile for token:', data['access_token'])
res = requests.get(CAS_BASE_URL + '/oauth2.0/profile', verify=False, headers={
'Accept':'application/json',
},
params={
'access_token' : data['access_token']
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)
# Test #2
print('Request access token for "X-service: http://example.com/api/v2", but with credentials for API v1')
res = requests.post(CAS_BASE_URL + '/oauth2.0/accessToken', verify=False,
headers={
'Accept':'application/json',
'X-service': 'http://example.com/api/v2'
},
data={
'grant_type':'client_credentials',
'client_id':'scdb_api_v1',
'client_secret': 'clientSecret11',
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)
data = res.json()
print('Request profile for token:', data['access_token'])
res = requests.get(CAS_BASE_URL + '/oauth2.0/profile', verify=False, headers={
'Accept':'application/json',
},
params={
'access_token' : data['access_token']
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)
# Test #3
print('Request access token for "X-service: http://example.com/api/v3", but with credentials for API v1')
res = requests.post(CAS_BASE_URL + '/oauth2.0/accessToken', verify=False,
headers={
'Accept':'application/json',
'X-service': 'http://example.com/api/v3'
},
data={
'grant_type':'client_credentials',
'client_id':'scdb_api_v1',
'client_secret': 'clientSecret11',
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)
data = res.json()
print('Request profile for token:', data['access_token'])
res = requests.get(CAS_BASE_URL + '/oauth2.0/profile', verify=False, headers={
'Accept':'application/json',
},
params={
'access_token' : data['access_token']
}
)
print('Response status code:', res.status_code)
print(res.text)
print()
if res.status_code != 200:
sys.exit(1)