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 cas-user+unsubscr...@apereo.org.
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