OAuth Integration Example - LinkedIn

Modified on: Fri, 26 Jun, 2020 at 1:36 PM

Configuring the iTDS for a NEW OAuth provider (LinkedIn)

In this article, we will look at an example provider, in this case, LinkedIn, but it should be relatively similar with all major providers.

The first step is to configure the application on the provider network, usually in the developer section and would be something like the following:


The next step is configuring where the OAuth provider (In this example LinkedIn) will redirect the browser to after the end-user has accepted the application. You should also receive the Client ID and Client Secret.



Configuring the OAuth settings on the iTDS

Now we have created our application with the provider we can configure the iTDS to use these settings within Maltego. If you are running your own internal OAuth application this information might already be provided for you. Browse to the iTDS interface. From the main page select "OAuth Settings" and then select "Add OAuth Setting" at the bottom of the list.



Initially, you are given the option to either re-use previous OAuth configurations or create a new one. In this case we want to create a new OAuth configuration and can select the “New OAuth configuration” checkbox. From there we will be asked to provide the details for this configuration (as described previously in this document).


The most important fields to remember are the Authenticator name, Access Token Variable Name and Public key (and private key as described in the following section) as these are the fields you will need to provide if you wish for other developers to use the same OAuth tokens within their transforms.


WHY DO WE USE A PUBLIC AND PRIVATE KEY?

Because tokens that are used within the OAuth communications are 50% of the authorization process (the other being the application keys), these tokens cannot be transmitted in the clear. As such this process is done with a public and private key in the following manner:

  • Maltego client knows about the public encryption key and this is sent during the discovery process.
  • Maltego client will retain the OAuth tokens after the analyst has logged into the provider.
  • When running the transform Maltego will send the tokens as follows:
    • Encrypt the token and token secret with the public encryption key (RSA/ECB/PKCS1Padding) or additional use of a symmetric key if one of the fields exceeds 501 bytes
    • Base64 encode both of them.
    • Concatenate these two base64, encrypted strings joined by a ‘$’ symbol.
    • The final string would be one of the following:  
      • B64(AESCrypt(Token)) $ B64(AESCrypt(TokenSecret)) $ B64(AESCrypt(RefreshToken)) $ B64(AESCrypt(ExpiresIn)) $ B64(RSACrypt(SymmetricKey)) 

      • B64(RSACrypt(Token)) $ B64(RSACrypt(TokenSecret)) $ B64(RSACrypt(RefreshToken)) $ B64(RSACrypt(ExpiresIn)) 

      • B64(AESCrypt(Token)) $ B64(AESCrypt(TokenSecret)) $ B64(RSACrypt(SymmetricKey)) 

      • B64(RSACrypt(Token)) $ B64(RSACrypt(TokenSecret)) 

  • The transform will know what the private key (either one generated when creating the OAuth configuration or one you already had) and be able to decode the token in as shown in the example in Implementing OAuth Settings in Code
  • Transform can then use the token and token secret to execute the API call against the provider to get the data

Public and private keys can be generated on the iTDS by clicking on the ‘Generate an RSA key pair’ link on the Add OAuth settings page:



Note You will note that the private key is NOT saved anywhere, it will be up to the developers to securely store this private key privately.


Configuring the iTDS for a previous OAuth provider (LinkedIn)

For this example we will be configuring the OAuth settings as per our current provider (LinkedIn) with the following:

META INFORMATION

This is the meta-information used to describe the OAuth setting.


Name: LinkedIn
Description: LinkedIn test
Version: OAuth 2.0


PROVIDER INFORMATION

This information is provided from the OAuth provider (LinkedIn)


Access token endpoint: https://www.linkedin.com/oauth/v2/accessToken/
Request token endpoint: https://www.linkedin.com/oauth/v2/authorization
Refresh Token Endpoint (where needed): https://www.linkedin.com/oauth/v2/accessToken
Authorization URL: https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id=CLIENT_ID_HERE&redirect_uri=http%3A%2F%2F127%2E0%2E0%2E1%3A54275%2Fcallback&scope=r_liteprofile%20r_emailaddress
Application Key: CLIENT_ID_HERE
Application Secret: CLIENT_SECRET_HERE


OTHER INFORMATION

This information is used within the application (Icon), the iTDS (Public Key) or in the transform code (Access token variable name). The icon field is a Base64 encoded 64x64 pixel icon to be used within the tool.


Icon: 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

Access Token Variable Name: maltego.web.api.key.linkedin
Variable Description: OAuth Credentials
Public Key
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAku0LLq+irbXHnQgZ+DQX
Hl81wg5oyqggMWMev408sJqhE7azAsB1xTkNU1Wi754EfqSwN5biAx5ge4UWAlGo
Fq47UImQI+1NyGAP0FCVZ50BySZxHCPAHADBdYGzGbA4Z46I3DwTwIw0ZJ1sJd8i
deJPNUR6lJB9hJtLpTVSVdsy1LT9ALaCdmYaLqwiR0hQwyufGr8R/kHT4499wMOy
9Km9FQqz5NbrFEfDBpQjuTqfLnmVMGxte9bJS1CJ0NMdnRRc3ZbS/5O5wPwelUQJ
XA9Gh2hobA5o3xkcHUPCauFepyp+gyEvcl4CSsfHXyU+Yqn6nhPn/FmUC7vdbYuq
n1LCVJ8pqZs71htq5LzeeVdc1QQz79jmexEVvokiL1X0uOtthvDrpBFBD6uQ9Cp6
fDjJUiH3zW8Xkf9jvxAdnkltaLR5zR1CT+iv4Hq6XTI5amUcvujHFU2KZGTdp14f
yZzgrO3HjAb5M+x1jwaXBKK1JAseO/bn8KHmCQm8APmsJC20kO0c19BXSdTvQ4jM
KXID6X+kLIUjZzCEx9tPdQwcn2X6jvFwF2AHVO6F4kQaPzXl8Vl8O+m52OGmNl6L
1it0rLrqCnodCy1tqleZ5TNNOzcO+AuaGks7shCvgnxckUdIZp7orAJthubuNI7H
zT/KJmyaLDFLXQypdx5GC8ECAwEAAQ==
-----END PUBLIC KEY-----


Once this has been completed you can click on ‘Add OAuth Setting’ at the bottom of the page to add this OAuth setting.

Pairing OAuth Settings with Transforms

Due to OAuth settings being specific per transform – one could have multiple transforms each using their own provider or none. OAuth settings are paired with transforms rather than with a specific seed. Within the iTDS interface for adding transforms you will now see a new section that will allow you to pick the OAuth settings required for this transform:



Implementing OAuth Settings in Code

To illustrate the use of OAuth in transforms, we assume you have followed the following steps.  

  1. Set up a developer Application with 3rd Party OAuth Provider 

  2. Configured OAuth settings in TDS  

  3. Paired OAuth Settings with Transform on the TDS 

  4. Configured a Seed on the TDS 

  5. Added the Transform Seed in the Client  

The following is an example code for a transform written using Maltego-TRX library that queries LinkedIn API against the logged-in user's access token:


from Crypto.Cipher import PKCS1_v1_5, AES
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from Crypto import Random
import base64
import requests

#maltego-trx library
from maltego_trx.maltego import UIM_TYPES
from maltego_trx.entities import Email
from maltego_trx.transform import DiscoverableTransform


class LinkedInEmail(DiscoverableTransform):
    """
    Returns LinkedIn Logged in user email
    """

    @classmethod
    def create_entities(cls, request, response):
        try:
            private_key_path = "/path/to/private_key.pem"
            encrypted_secrets = request.getTransformSetting('maltego.web.api.key.linkedin')
            encrypted_fields = encrypted_secrets.split("$")

            aes_key = cls._rsa_decrypt(private_key_path, encrypted_fields[2])
            token = cls._aes_decrypt(aes_key, encrypted_fields[0])
            api_url = "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))"

            result = requests.get(api_url, headers={'Authorization': 'Bearer {}'.format(token)})

            email = result.json()['elements'][0]['handle~']['emailAddress']
            response.addEntity(Email, email)
        except (Exception):
            response.addUIMessage("Error: " + str(e), UIM_TYPES["Fatal"])

    @staticmethod
    def _rsa_decrypt(private_key_path=None, ciphertext=None):
        """
        RSA Decryption funtion, returns decrypted plaintext in b64 encoding
        """
        try:
            dsize = SHA.digest_size
            sentinel = Random.new().read(20 + dsize)
            ciphertext = base64.b64decode(ciphertext)
            private_key = RSA.import_key(open(private_key_path).read())
            cipher = PKCS1_v1_5.new(private_key)
            plaintext = cipher.decrypt(ciphertext, sentinel)
        except (Exception):
            raise

        return plaintext

    @staticmethod
    def _aes_decrypt(key=None, ciphertext=None):
        """
        AES Decryption funtion, returns decrypted plaintext value
        """
        unpad = lambda s: s[:-ord(s[len(s) - 1:])]
        try:
            key = base64.b64decode(key)
            ciphertext = base64.b64decode(ciphertext)
            cipher = AES.new(key, AES.MODE_ECB)
            plaintext = unpad(cipher.decrypt(ciphertext)).decode('utf8')
        except (Exception):
            raise
        return plaintext


Testing the Transform

Add the seed to the desktop client and install it:



Go to Service Manager and click 'Sign In'.



 Authenticate using LinkedIn account



You should be presented by a success page. Close this and move back to the desktop client



Drop an Alias entity on to the graph and run the transform (Value of input entity does not take any part in the above-provided example code)



You should get the logged-in user email address.

Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.