Accessing the Secure Store from a Timer Job, more than once.

A neat feature within SharePoint is the Secure Store Service. It gives us the opportunity to store account credentials for external systems without having to worry about encryption, where to store it securely, etc. SharePoint handles it all for us. Another plus for SharePoint development.

Another neat feature is the Timer Service. This concept of recurring jobs is not new, as Windows Tasks can do it, and everything since the 80s has it.

I ran into an issue combining the two however. It appears as though the two don’t play well together.

A little background: we have data in SharePoint that is uploaded to a FTP site (using FTP credentials), then we call a web service (using API credentials) to say “Hey, the file is there”. Then we periodically check the status of the data (API Credentials), and when it’s completed, we download a load of data it back into SharePoint.

We decided to use a timer to post the item, then check the status, and download. This way the user could upload and move on, set it and forget it.

Since there is this neat service called Secure Store that I previously mentioned, we decided to store the FTP and API credentials in there.

When the check status timer job ran, it worked. When the upload timer ran, it would error (below), and then both timer jobs would error after that until we were able to restart the timer service.

System.ServiceModel.EndpointNotFoundException: Secure Store Service did not performed the operation.

Yes, that is a typo, and no, not from me, that’s from Microsoft.

To make matters worse, everything worked fine when running the same code from a web part. So frustrating…

So our fix? We had to null out our objects. See code below:

public static UserAccount GetSecureStoreAccount(SPSite site, string secureStoreAppID)
        {
            UserAccount secureUser = new UserAccount();
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite elevatedSite = new SPSite(site.ID))
                {
                    SPServiceContext context = SPServiceContext.GetContext(site);
                    SecureStoreServiceProxy ssp = new SecureStoreServiceProxy();
                    ISecureStore iss = ssp.GetSecureStore(context);
                    using (SecureStoreCredentialCollection myCreds = iss.GetCredentials(secureStoreAppID))
                    {
                        foreach (SecureStoreCredential cred in myCreds)
                        {
                            switch (cred.CredentialType)
                            {
                                case SecureStoreCredentialType.UserName:
                                    secureUser.UserName = ReadSecureString(cred.Credential);
                                    break;
                                case SecureStoreCredentialType.Password:
                                    secureUser.Password = ReadSecureString(cred.Credential);
                                    break;
                            }
                            cred.Dispose();
                        }
                    }
                    context = null;
                    ssp = null;
                    iss = null;
                }
            });
            return secureUser;
        }

I added the cred.Dispose() (though the using statement on the collection disposes of each cred within), and then I nulled out each object when I was done. I don’t know if they all have to be nulled, I didn’t test each one individually, but this works.

Hope this helps. Happy SharePointing!

Leave a Reply

Up ↑

Discover more from David Lozzi

Subscribe now to keep reading and get access to the full archive.

Continue reading