Keystone scoped or unscoped?

对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的理解是不是对的。


  • 获取一个V3的unscoped token


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



  • 拿一个project list

 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']))

这个route的实现中,其实是没有对令牌是否关联project信息做限定的,而在另一个route里:


# 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']))

实现代码里其实是校验了token是否是project scoped的token。

            if user_token_ref.project_scoped:
                creds['tenant_id'] = user_token_ref.project_id
            else:
                LOG.debug('Invalid tenant')


换言之,如果用管理员的端口访问的话,令牌必须是一个project scoped的令牌。



那么,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
Date: Wed, 07 Sep 2016 09:41:50 GMT
Server: Apache/2.4.7 (Ubuntu)
Vary: X-Auth-Token
x-openstack-request-id: req-b4579fb1-cb22-4e2f-859b-3ea396c266cc
Content-Length: 948
Content-Type: application/json
Via: 1.1 shzintpr02.sh.intel.com
Proxy-Connection: Keep-Alive
Connection: Keep-Alive


{"links": {"self": "http://10.239.159.68/identity/v3/auth/projects", "previous": null, "next": null}, "projects": [{"is_domain": false, "description": "", "links": {"self": "http://10.239.159.68/identity/v3/projects/150ca560e068435fa0db7ca0c7f0cf74"}, "enabled": true, "id": "150ca560e068435fa0db7ca0c7f0cf74", "parent_id": "default", "domain_id": "default", "name": "alt_demo"}, {"is_domain": false, "description": "", "links": {"self": "http://10.239.159.68/identity/v3/projects/9e910a2e15e74a369eac82dda9e7e015"}, "enabled": true, "id": "9e910a2e15e74a369eac82dda9e7e015", "parent_id": "default", "domain_id": "default", "name": "demo"}, {"is_domain": false, "description": "Bootstrap project for initializing the cloud.", "links": {"self": "http://10.239.159.68/identity/v3/projects/caaa06cf868e44c2882623afd34eea60"}, "enabled": true, "id": "caaa06cf868e44c2882623afd34eea60", "parent_id": "default", "domain_id": "default", "name": "admin"}]}

你可能感兴趣的:(OpenStack)