对Keystone稍有了解的人应该知道,Keystone有两大类型的token,即scoped token与unscoped token。具体的细分不再赘述。之所以再次注意到这个问题是因为最近有人问到我这个问题,如何通过unscoped token拿一个scoped token?
我随口说道,先拿一个unscoped token,通过这个token去拿一个project list,将unscoped token和具体的project相关联,就可以去获取一个scoped token。之所以这样肯定是因为V2就是这样做的,而且千真万确,我之前在写书的时候不知道验证过多少回。V3是不是也是这样实现的,不记得真切,但据我所知,应该逻辑至少是一致的。
于是我又做了一次实验。
dave@shldeOTCopen005:~$ curl -g -i -X GET http://10.239.48.152:35357/v3/projects -H "Accept: application/json" -H "X-Auth-Token: dbe47a2d6ddd4ae895029cd251def4f4"
HTTP/1.1 403 Forbidden
Date: Wed, 07 Sep 2016 09:19:55 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
x-openstack-request-id: req-2e2d29e8-ad9d-4cbe-befe-90e12412ed91
Content-Length: 139
Content-Type: application/json
{"error": {"message": "You are not authorized to perform the requested action: identity:list_projects", "code": 403, "title": "Forbidden"}}
not authorized???!!!!
难道V3不是这样实现的?于是查找文档,发现官网对unscoped token的描述已经变了很多。
“An unscoped token contains neither a service catalog, any roles, a projectscope, nor a domain scope. Their primary use case is simply to prove your identity to keystone at a later time (usually to generate scoped tokens),without repeatedly presenting your original credentials.”
看吧,根本没有说可以用unscoped token来拿一个project list,从而获取scoped token的目的。究竟发生了什么?
回过头来看看V2吧,我开始怀疑我对V2的理解是不是对的。
curl -i -H "Content-Type: application/json" -d '
{ "auth": {
"identity": {
"methods": ["password"],
"password": {
"user": {
"name": "admin",
"domain": { "id": "default" },
"password": "zaq12wsx"
}
}
}
}
}' http://10.239.159.68:5000/v3/auth/tokens ; echo
curl -g -i -X GET http://10.239.159.68:5000/v2.0/tenants -H "Accept: application/json" -H "X-Auth-Token: 8b7c67af668c4065bc29a879b5345adb"
{"tenants_links": [], "tenants": [{"description": "", "enabled": true, "id": "150ca560e068435fa0db7ca0c7f0cf74", "name": "alt_demo"}, {"description": "", "enabled": true, "id": "9e910a2e15e74a369eac82dda9e7e015", "name": "demo"}, {"description": "Bootstrap project for initializing the cloud.", "enabled": true, "id": "caaa06cf868e44c2882623afd34eea60", "name": "admin"}]}
看来V2是可以的,换个端口试试
dave@openstack-dev:~$ curl -g -i -X GET http://10.239.159.68:35357/v2.0/tenants -H "Accept: application/json" -H "X-Auth-Token: 8b7c67af668c4065bc29a879b5345adb"
HTTP/1.1 401 Unauthorized
Date: Wed, 07 Sep 2016 09:29:26 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
x-openstack-request-id: req-c1c60bdd-6711-4d31-a152-0fb07cd221ae
WWW-Authenticate: Keystone uri="http://10.239.159.68/identity"
Content-Length: 114
Content-Type: application/json
Via: 1.1 shzintpr02.sh.intel.com
Cache-Control: proxy-revalidate
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Proxy-support: Session-based-authentication
{"error": {"message": "The request you have made requires authentication.", "code": 401, "title": "Unauthorized"}}
看来如果用35357管理员端口去访问会得到一样的错误。好吧,也只有硬着头皮去翻代码了。找来找去终于发现V2对于不同的访问端口定义了两个不同的route。
# keystone\keystone\assignment\routers.py
class Public(wsgi.ComposableRouter):
def add_routes(self, mapper):
tenant_controller = controllers.TenantAssignment()
mapper.connect('/tenants',
controller=tenant_controller,
action='get_projects_for_token',
conditions=dict(method=['GET']))
# keystone\keystone\resource\routers.py
class Admin(wsgi.ComposableRouter):
def add_routes(self, mapper):
# Tenant Operations
tenant_controller = controllers.Tenant()
mapper.connect('/tenants',
controller=tenant_controller,
action='get_all_projects',
conditions=dict(method=['GET']))
if user_token_ref.project_scoped:
creds['tenant_id'] = user_token_ref.project_id
else:
LOG.debug('Invalid tenant')
那么,V2弄清楚了,V3呢?
V3因为引入了policy,所以不再需要通过不同的访问端口来做区分,可以直接通过policy来实现,所以去翻了翻policy的定义,豁然开朗,原来如此:
"identity:get_auth_projects": "",
"identity:get_auth_domains": "",
"identity:list_projects_for_user": "",
"identity:list_domains_for_user": "",
也就是说可能用的不是同样的route来实现此次目的,看看route定义,果然:
# keystone\keystone\auth\routers.py
self._add_resource(
mapper, auth_controller,
path='/auth/projects',
get_action='get_auth_projects',
rel=json_home.build_v3_resource_relation('auth_projects'))
self._add_resource(
mapper, auth_controller,
path='/auth/domains',
get_action='get_auth_domains',
rel=json_home.build_v3_resource_relation('auth_domains'))
做个试验来验证一下吧:
dave@openstack-dev:~/scripts$ curl -g -i -X GET http://10.239.159.68:35357/v3/auth/projects -H "Accept: application/json" -H "X-Auth-Token: 342796581b4541fc8a8c38b394c2b6c1" (此为一个unscoped token)
HTTP/1.1 200 OK