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)

Reply via email to