Stark & Wayne

Code spelunking to build a CF Plugin

This is a quick "how to" for how Long found the information he needed to build the cf info plugin.

Following a trail of breadcrumbs

Determine the requirements:

  1. Print the currently targeted org and space
  2. Print the API version and endpoint
  3. Print the user id of the current user (similar to whoami in *nix OSes).

Fulfilling the requirements:

This information comes from cf target, so first we'll take a look in target.go.

How to get the file path? Searching for CF_HOME (environmental variable storing the home directory) shows that it is defined in config_helpers.go. Now what to do with that information:

What to do with all of that

Basically everything in reverse. You supply the default file path, which is config.json, to NewRepositoryFromFilepath. config.json has the org, space, API endpoint, API version, and Access Token. The existing cf code decodes the Access Token and the UserEmail method extracts the email address from that information. Everything is just pulled directly from the repository you just defined.

Addendum: What is going on to get that email anyway?

Let's take a quick look in config.json. The 7th line should be the Access Token, which should look similar to this:

"AccessToken": "bearer eyJhbGciOiJSUzI1NiJ9.eyJqdGkiOiI3NzI2ZDE2MS1hNWUzLTQwZjMtYTEzYy00OTlmMDNjOTBhZGIiLCJzdWIiOiI2Y2I5MTA0Yy1hZTMxLTQxYTMtOGQ4MS1jYjUxZjg0MTk5ZTMiLCJzY29wZSI6WyJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwiY2xvdWRfY29udHJvbGxlci53cml0ZSIsIm9wZW5pZCIsInBhc3N3b3JkLndyaXRlIiwic2NpbS5yZWFkIiwic2NpbS53cml0ZSJdLCJjbGllbnRfaWQiOiJjZiIsImNpZCI6ImNmIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9pZCI6IjZjYjkxMDRjLWFlMzEtNDFhMy04ZDgxLWNiNTFmODQxOTllMyIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsImlhdCI6MTQxNzgxMTU3NywiZXhwIjoxNDE3ODEyMTc3LCJpc3MiOiJodHRwczovL3VhYS41NC4xNzQuMjI5LjExOS54aXAuaW8vb2F1dGgvdG9rZW4iLCJhdWQiOlsic2NpbSIsIm9wZW5pZCIsImNsb3VkX2NvbnRyb2xsZXIiLCJwYXNzd29yZCJdfQ.XNaYq8rxpvwWx9kySIDqbKs0BuyeOMMwAPb5YQaT-9MIyr3YalCE_2gTg-fl0xulj4u-VoNme3OGZ2T3tFFUfBKgo3U7R_pl5OpcaetKslbvKtYpne7N30KMQySMqVVVooGqlReoI_n5m5O7ZIASiG8P1QtwuVrZPkPhbjsGfBE",

Source: The above is the access token from a now-destroyed TryCF instance.

This is a JSON Web Token (JWT). You can read about JWT here. For now, all I really care about is that its structure is <header>.<claims>.<signature>. The <claims> section of the above token is between the two periods:

eyJqdGkiOiI3NzI2ZDE2MS1hNWUzLTQwZjMtYTEzYy00OTlmMDNjOTBhZGIiLCJzdWIiOiI2Y2I5MTA0Yy1hZTMxLTQxYTMtOGQ4MS1jYjUxZjg0MTk5ZTMiLCJzY29wZSI6WyJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwiY2xvdWRfY29udHJvbGxlci53cml0ZSIsIm9wZW5pZCIsInBhc3N3b3JkLndyaXRlIiwic2NpbS5yZWFkIiwic2NpbS53cml0ZSJdLCJjbGllbnRfaWQiOiJjZiIsImNpZCI6ImNmIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9pZCI6IjZjYjkxMDRjLWFlMzEtNDFhMy04ZDgxLWNiNTFmODQxOTllMyIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsImlhdCI6MTQxNzgxMTU3NywiZXhwIjoxNDE3ODEyMTc3LCJpc3MiOiJodHRwczovL3VhYS41NC4xNzQuMjI5LjExOS54aXAuaW8vb2F1dGgvdG9rZW4iLCJhdWQiOlsic2NpbSIsIm9wZW5pZCIsImNsb3VkX2NvbnRyb2xsZXIiLCJwYXNzd29yZCJdfQ

If you paste that information into Base 64 Decode, you can see the user's credentials - including the email field. (For TryCF the user_name and email are both admin.) If you paste in the above and decode it, you will see:

{"jti":"7726d161-a5e3-40f3-a13c-499f03c90adb","sub":"6cb9104c-ae31-41a3-8d81-cb51f84199e3","scope":["cloud_controller.admin","cloud_controller.read","cloud_controller.write","openid","password.write","scim.read","scim.write"],"client_id":"cf","cid":"cf","grant_type":"password","user_id":"6cb9104c-ae31-41a3-8d81-cb51f84199e3","user_name":"admin","email":"admin","iat":1417811577,"exp":1417812177,"iss":"https://uaa.54.174.229.119.xip.io/oauth/token","aud":["scim","openid","cloud_controller","password"]}

Feel free to try it with your own Access Token! :)