How the token ID of the OpenStack Keystone is generated and the content source analysis

Source: Internet
Author: User
Tags auth class manager function prototype uuid

Keystone Version information: 2:8.1.0-2~U14.04+MOS4


In the token message that is returned when the request is token, the token ID is a string of gaaaa at the beginning, shaped like

gaaaaabaxgptr5hdq391yr5ekgz8brdva--boumppvnjhqdbyciusskfv7od48zamsqzozqxawxrzhp8tawhrzki9gxmqsrrsnkn7m4vdvc7pt56rfg5oz8l _jl_8yxtjduxgxsthrtc2sdanlzxoodf61msmcp_ra_iqy0rogwxnnsdz

Nonsense not much said, directly to see the request URL path

Http://192.168.0.2:5000/v2.0/tokens

The 5000 port corresponds to the keystone-main,v2.0 indicating the Keystone use version, tokens is the requested path

Keystone's design is based on WSGI, so find the tokens routing code


You can see tokens corresponding controller for token_controllers, this controller corresponding code in keystone/token/ In controllers.py, the action is authenticate, that is, the authenticate () function in the corresponding Controllers.auth ()

@dependency. Requires (' Assignment_api ', ' catalog_api ', ' Identity_api ',
' resource_api ', ' Role_api ', ' Token_provider_api ',
' Trust_api ')
class Auth (controller. V2controller): ...
Def authenticate (self, Context, Auth=none):
...
        (token_id, Token_data) = Self.token_provider_api.issue_v2_token (
            auth_token_data, Roles_ref=roles_ref, Catalog_ REF=CATALOG_REF)

        # Note (wanghong): "We consume a trust use only when We are using Trusts
        # and have successfully are Sued a token.
        If CONF.trust.enabled and ' trust_id ' in auth:
            self.trust_api.consume_use (auth[' trust_id ']) return

        Token_ Data

As you can see here, authenticate () returns the Token_data, so we find the Token_data generated code that

        (token_id, Token_data) = Self.token_provider_api.issue_v2_token (
            auth_token_data, Roles_ref=roles_ref, Catalog_ REF=CATALOG_REF)

Continue tracking Token_provider_api, this function is under keystone/token/provider.py

Continue tracking Self.driver.issue_v2_token. That is, directory keystone/token/providers/fernet/core.py

@dependency. Requires (' Trust_api ')
class Provider (common. Baseprovider): ...
def issue_v2_token (self, token_ref, Roles_ref=none, catalog_ref=none):
...
        token_id = Self.token_formatter.create_token (user_id, Expires_at,
                                                     audit_ids,
                                                     methods=method_names
                                                     , project_id=project_id)
        self._build_issued_at_info (token_id, V3_token_data)
        # Convert V3 to v2 token data and Build V2 Catalog
        token_data = Self.v2_token_data_helper.v3_to_v2_token (v3_token_data)
        token_data[' Access ' [' token '] [' id '] = token_id return

        token_id, Token_data

Skip to Token_formatter to continue tracking

keystone/token/providers/fernet/token_formatters.py

Class Tokenformatter (Object):. Def create_token (self, user_id, Expires_at, Audit_ids, Methods=none, Domain_id=none, Project_id=none, Trust_id=none, Federated_info=none): "" "Given a set of P
        Ayload attributes, generate a Fernet token. "" "
                If trust_id:version = trustscopedpayload.version payload = trustscopedpayload.assemble ( USER_ID, methods, project_id, Expires_at, Audit_ids , trust_id) elif project_id and federated_info:version = Federatedprojectscopedpayloa
                D.version payload = federatedprojectscopedpayload.assemble (user_id, methods,
        project_id, Expires_at, Audit_ids, Federated_info) Elif domain_id and federated_info:version = Federateddomainscopedpayload.versIon payload = Federateddomainscopedpayload.assemble (user_id, methods, domain_id, Expires_at, Audit_ids, federated_info) elif fe Derated_info:version = federatedunscopedpayload.version Payload = Federatedunscopedpayload.assemb
                Le (user_id, methods, Expires_at, Audit_ids, Federated_info) Elif project_id:version = projectscopedpayload.version payload = Proje Ctscopedpayload.assemble (user_id, methods, project_id, ex
            Pires_at, audit_ids) elif domain_id:version = domainscopedpayload.version
                Payload = Domainscopedpayload.assemble (user_id, methods, domain_id,
Expires_at,                Audit_ids) else:version = unscopedpayload.version Payload = Unscopedpaylo

        Ad.assemble (user_id, methods, Expires_at, Audit_ids) Versioned_payload = (version,) + Payload serialized_payload = msgpack.packb (versioned_payload) token = Self.pack (serialized_payload) # Note (Lbragstad): We should warn against fernet this tokens over # 2 Characters in length.
        This is mostly due to persisting the tokens # into a backend store of some kind that might have a limit of 255 # characters. Even though Keystone isn ' t storing a Fernet token # anywhere, we can ' t say it isn ' t being stored else WI
        Th # Those kind of backend constraints. If Len (token) > 255:log.info (_li (' Fernet token created with length of%d ' Chara
         Cters, which exceeds 255 characters '),            Len (token)) return token
 

Add log to view the load parameters required for token_id log.info ((user_id, Expires_at, Audit_ids, methods)


Add log print Log.info to function entry (domain_id, project_id, trust_id, Federated_info)

As can be seen from the log, only project_id this parameter (because of the V2 API, so only project_id), so go elif project_id This judgment statement, call Projectscopedpayload to handle the data


keystone/token/providers/fernet/token_formatters.py

Class Projectscopedpayload (basepayload): Version = 2 @classmethod def assemble (CLS, user_id, Methods, project

        _id, Expires_at, Audit_ids): "" "Assemble the payload of a project-scoped token. :p Aram User_id:id of the user in the token request:p Aram Methods:list of authentication methods used:p Aram Project_id:id of the project to scope to:p Aram Expires_at:datetime of the token ' s expiration:p Ara M audit_ids:list of the token ' s audit IDs:returns:the payload of a project-scoped token "" "B_ user_id = Cls.attempt_convert_uuid_hex_to_bytes (user_id) methods = Auth_plugins.convert_method_list_to_integer (Met Hods) b_project_id = Cls.attempt_convert_uuid_hex_to_bytes (project_id) Expires_at_int = cls._convert_time_
                           String_to_int (expires_at) b_audit_ids = List (Map (provider.random_urlsafe_str_to_bytes, Audit_ids)) return (b_user_id, methods, b_project_id, Expires_at_int, B_audit_ids)
 

You can see that projectscopedpayload will turn the input string into 16, convert the numeric value to type int, and then return to the code that turns the string into 16.

keystone/token/providers/fernet/token_formatters.py

Class Basepayload (object): ...
    @classmethod
    def attempt_convert_uuid_hex_to_bytes (CLS, value): ""
        attempt to convert value to bytes or return Value.

        :p Aram Value:value to attempt to convert to bytes
        : Returns:tuple containing boolean indicating whether US er_id
                  is stored as bytes and UUID value as bytes or the original value

        ""
        Try: Return
            (True, Cls.convert _uuid_hex_to_bytes (value))
        except ValueError:
            # This might is not being a UUID, depending on the situation (i.e.
            # Federation) return
            (False, value)

After projectscopedpayload treatment, the payload and Versioned_payload were

As a result, the character literals has been converted into a 16 form

Come back and see the code.

        Versioned_payload = (version,) + Payload
        log.info ("###### payload=%s,versioned_payload=%s"% (payload,versioned_ Payload))
        serialized_payload = msgpack.packb (versioned_payload)
        with open ("/tmp/yxj.log", "w+") as F:
            F.write (serialized_payload)
        token = self.pack (serialized_payload)
        log.info ("###### token=%s"% token)

The next operation is to serialize the load, because the encoding problem directly print log will be an error, so the redirect to the text out to see the serialized content, the content is

Well, I don't know what it is anymore. Finally, using the pack () method to process the serialized payload, it becomes the token format that we see eventually


You can continue to look at the function prototype of the pack

    Def pack (self, Payload): "" "
        pack a payload for transport as a token.
        " " # base64 padding (if any) isn't Url-safe return
        self.crypto.encrypt (payload). Rstrip (' = ')

If you want to continue to further understand, you can follow the code. Because I'm going to have to jump out of Keystone's bag.







Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.