Recently I worked on a project where the customer wanted to publish and share information from their website to LinkedIn to reach out to broader audiences and to involve user interaction. The solution is based on Sharepoint 2010. LinkedIn should not be used as a fully integrated identity provider but as an connector to some of the services on LinkedIn. Here are some of the experiences I made through the project.

linkedinloginn

LinkedIn restrictions

We wanted to share articles on LinkedIn to enable discussion on both LinkedIn and on the portal site. When loggedin with Linkedin in the portal the user could post comments directly from the site and get all comments from Linkedin. To get any data from Linkedin API it requires to call services on behalf of an authenticated user, otherwise no data can be retreived from the API. This was a drawback, because comments from other user could not be shown in the portal without being logged in, even if the comments is in a public Linkedin group. There was also a lack of possibility to share rich data using the Group API . To share content we created a new discussion post on LinkedIn. This has a limitation on content length and rich text formatting, but it has a submitted url property, so we used that url to share a link to the article in the portal.

Authentication overview

LinkedIn uses OAuth (2.0) for authentication and API access. OAuth provides a standard for authentication and authorization functionality for client and server applications. This allows the Sharepoint portal to accept and verify identities from LinkedIn and access data on behalf of the user in a secure way, and without the users every revealing their passwords.

Oauth protocol uses security tokens to communicate between client and server. The API keys is identifying the application and is required to make API calls. The initial request uses the api key to get a access token.  The access token is needed in all further calls to access data from LinkedIn on behalf of the user. No data access is allowed without an access token. The access token is retrieved by redirecting to LinkedIn’s authorization dialog.

The permissions that are granted to the application is listed in the authorization box (this permissions are specified from which data the portal will be using). If the user allows access then there is a redirection back to the portal with a valid access token.  This access token was implemented to be stored in a session and used throughout all further calls to the LinkedIn API from the portal.

Authentication api: https://developer.linkedin.com/documents/authentication

Linkedin Certificate

We had some trouble making server requests to LinkedIn with this exception: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. —> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure. at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception) at…

The solution is to install the SSL certificate on the web server. We could solve by adding Verisign root 3 certificate as trusted source (via Central admin > Security -> Manage trust):

http://www.verisign.com/support/roots.html

Root 3 – VeriSign Class 3 Primary CA – G5  (file: PCA-3G5.pem)

However, the exception was still throwing on one of the servers after the certificated was installed. To fix this issue we added a workaround in code. Before calling LinkedIn, a bypass for SSL validation check was added:

    // fix for bypassing any certificate errors
ServicePointManager.ServerCertificateValidationCallback =
delegate(object s, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

 

Implementation

To implement OAuth required for the LinkedIn integration we are used a third party OAUth provider library in .NET called DotNetOpenAuth. DotNetOpenAuth library requires a token manager that handles the storage and retrieval of the OAuth tokens. This token processing is handled by a custom class that implements the IConsumerTokenManager interface. The IConsumerTokenManager interface is called by the DotNetOpenAuth library to handle the storage and retrieval of the tokens that are needed for user authentication in the OAuth standard. For our solution the class that implements the interface and storage handling is done with server session variables. It stores the Linkedin Api  keys  initially and before the authentication process starts.

DotNetOpenAuth provides a WebConsumer class for the service requests.  This class uses the Tokenmanager and uris for the requests. We implemented the api uris and processed the request/response data from Linkedin with mapping to ServiceEntities objects that represents the structure of the data expected or returned from Linkedin. When this structure is in place the objects can be easily  mapped. To generate the api uris and the object formats, study the api documentation https://developer.linkedin.com/rest

LinkedIn permissions scopes are setup in the RequestTokenEndpoint. If permissions need to be changed then this endpoint needs to be changed: https://api.linkedin.com/uas/oauth/requestToken?scope=r_fullprofile rw_groups r_contactinfo r_emailaddress. The scope determines which permission the application wants to access on behalf of the user.