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.