//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Libraries/CredentialsManager/CredentialsManager.sg // // Note: // // This library is mostly a wrapper for the CredentialsManagerContract. // It simplifies connecting to and using the Credentials Manager service. // Most of the request/response messages of the CredentialsManagerContract // are exposed as static methods on the CredentialsManager class. // // For each request, two static methods are provided; one that borrows a // reference to CredentialsManagerContract.Imp, and one that does not. // The methods that do not take a reference will create and connect a // channel to the Credentials Manager service, perform the request (by // calling the other method overload) and then delete the channel. // Applications that need issue only a small number of requests can use the // no-reference variations; apps that will issue many requests can call the // ConnectService() method, and call the variations that do take an endpoint, // then delete the endpoint when necessary. // using System; using Microsoft.Contracts; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Directory; using Microsoft.SingSharp; namespace Microsoft.Singularity.Security { public sealed /* static */ class CredentialsManager { private CredentialsManager() {} public static CredentialsManagerContract.Imp! ConnectService() { CredentialsManagerContract.Imp! manager; CredentialsManagerContract.Exp! manager_exp; CredentialsManagerContract.NewChannel(out manager, out manager_exp); DirectoryServiceContract.Imp! rootds = DirectoryService.NewClientEndpoint(); rootds.SendBind(Bitter.FromString2(CredentialsManagerContract.ChannelPath), manager_exp); switch receive { case rootds.AckBind(): break; case rootds.NakBind(exp, error): delete exp; delete manager; delete rootds; throw new Exception(String.Format("Failed to bind to control channel '{0}': error {1}", CredentialsManagerContract.ChannelPath, error)); } delete rootds; switch receive { case manager.Success(): return manager; } } public static string! CredErrorToString(CredError error) { switch (error) { case CredError.NoError: return "No error"; case CredError.InternalError: return "Internal error"; case CredError.NoMatchingCredentials: return "No matching credentials"; case CredError.MatchingEntryExists: return "A matching entry already exists"; case CredError.NoMatchingAuthenticationProtocol: return "No authentication protocol exists with that name."; case CredError.NoEntryFound: return "No matching entry was found."; case CredError.ContractNotSupported: return "The channel provided does not implement any supported contract."; case CredError.InvalidArguments: return "Invalid arguments were provided."; case CredError.EvidenceTypeNotSupported: return "The authentication protocol that was selected does not support the type of evidence used by the credentials."; default: return "(" + ((int)error) + ")"; } } public static string! GssErrorCodeToString(GssErrorCode error) { switch (error) { case GssErrorCode.InternalError: return "Internal error"; case GssErrorCode.ServerRefusedAuthentication: return "The server refused authentication."; default: return ((int)error).ToString(); } } public static void CreateSupplicant( CredentialsManagerContract.Imp! manager, string! authenticationProtocol, string! credentialsName, string! tag, [Claims]ServiceContract.Exp! exp) { CredentialsId id = new CredentialsId(); id.CredentialsName = Bitter.FromString2(credentialsName); id.Tag = Bitter.FromString2(tag); manager.SendCreateSupplicant(Bitter.FromString2(authenticationProtocol), id, exp); switch receive { case manager.Ok(): break; case manager.RequestFailed(error): throw new CredentialsManagerException("The supplicant could not be created.", error); } } public static void CreateSupplicant( string! authenticationProtocol, string! credentialsName, string! tag, [Claims]ServiceContract.Exp! exp) { CredentialsManagerContract.Imp! manager = ConnectService(); try { CreateSupplicant( manager, authenticationProtocol, credentialsName, tag, exp); } finally { delete manager; } } public static void CreateSupplicantForProtocol( CredentialsManagerContract.Imp! manager, string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, [Claims]ServiceContract.Exp:Start! exp, out string! credentialsName, out string! tag) { ProtocolTuple tuple = new ProtocolTuple(); tuple.ApplicationProtocol = Bitter.FromString2(applicationProtocol); tuple.ServiceAddress = Bitter.FromString2(serviceAddress); tuple.AuthenticationProtocol = Bitter.FromString2(authenticationProtocol); tuple.Realm = Bitter.FromString2(realm); manager.SendCreateSupplicantForProtocol(tuple, exp); switch receive { case manager.AckCreateSupplicantForProtocol(credentialsSelected): credentialsName = Bitter.ToString2(credentialsSelected.CredentialsName); tag = Bitter.ToString2(credentialsSelected.Tag); credentialsSelected.Dispose(); break; case manager.RequestFailed(error): throw new CredentialsManagerException("The authentication supplicant could not be created.", error); } } public static void CreateSupplicantForProtocol( string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, [Claims]ServiceContract.Exp:Start! exp, out string! credentialsName, out string! tag) { CredentialsManagerContract.Imp! manager = ConnectService(); try { CreateSupplicantForProtocol( manager, applicationProtocol, serviceAddress, authenticationProtocol, realm, exp, out credentialsName, out tag); } finally { delete manager; } } public static void AddCredentials( CredentialsManagerContract.Imp! manager, string! credentialsName, string! tag, string! password, bool replace) { CredentialsId id = new CredentialsId(); id.CredentialsName = Bitter.FromString2(credentialsName); id.Tag = Bitter.FromString2(tag); manager.SendAddCredentials(id, Bitter.FromString2(password), replace); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to add credentials failed.", error); case manager.ChannelClosed(): throw new CredentialsManagerException(ChannelClosedMsg); } } public static void AddCredentials( string! credentialsName, string! tag, string! password, bool replace) { CredentialsManagerContract.Imp! manager = ConnectService(); try { AddCredentials(manager, credentialsName, tag, password, replace); } finally { delete manager; } } public static void DeleteCredentials( CredentialsManagerContract.Imp! manager, string! credentialsName, string! tag) { CredentialsId id = new CredentialsId(); id.CredentialsName = Bitter.FromString2(credentialsName); id.Tag = Bitter.FromString2(tag); manager.SendDeleteCredentials(id); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to delete credentials failed.", error); case manager.ChannelClosed(): throw new CredentialsManagerException(ChannelClosedMsg); } } public static void DeleteCredentials( string! credentialsName, string! tag) { CredentialsManagerContract.Imp! manager = ConnectService(); try { DeleteCredentials(manager, credentialsName, tag); } finally { delete manager; } } public static void DeleteAllCredentials(CredentialsManagerContract.Imp! manager) { manager.SendDeleteAllCredentials(); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to delete all credentials failed.", error); case manager.ChannelClosed(): throw new CredentialsManagerException(ChannelClosedMsg); } } public static void DeleteAllCredentials() { CredentialsManagerContract.Imp! manager = ConnectService(); try { DeleteAllCredentials(manager); } finally { delete manager; } } public static void AddProtocolMapping( CredentialsManagerContract.Imp! manager, string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, string! credentialsName, string! tag, bool replace) { ProtocolTuple tuple = new ProtocolTuple(); tuple.ApplicationProtocol = Bitter.FromString2(applicationProtocol); tuple.ServiceAddress = Bitter.FromString2(serviceAddress); tuple.AuthenticationProtocol = Bitter.FromString2(authenticationProtocol); tuple.Realm = Bitter.FromString2(realm); CredentialsId id = new CredentialsId(); id.CredentialsName = Bitter.FromString2(credentialsName); id.Tag = Bitter.FromString2(tag); manager.SendAddProtocolMapping(tuple, id, replace); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to add a protocol mapping failed.", error); } } public static void AddProtocolMapping( string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, string! credentialsName, string! tag, bool replace) { CredentialsManagerContract.Imp! manager = ConnectService(); try { AddProtocolMapping( manager, applicationProtocol, serviceAddress, authenticationProtocol, realm, credentialsName, tag, replace); } finally { delete manager; } } public static void DeleteProtocolMapping( CredentialsManagerContract.Imp! manager, string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm) { ProtocolTuple tuple = new ProtocolTuple(); tuple.ApplicationProtocol = Bitter.FromString2(applicationProtocol); tuple.ServiceAddress = Bitter.FromString2(serviceAddress); tuple.AuthenticationProtocol = Bitter.FromString2(authenticationProtocol); tuple.Realm = Bitter.FromString2(realm); manager.SendDeleteProtocolMapping(tuple); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to delete a protocol mapping failed.", error); } } public static void DeleteProtocolMapping( string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm) { CredentialsManagerContract.Imp! manager = ConnectService(); try { DeleteProtocolMapping( manager, applicationProtocol, serviceAddress, authenticationProtocol, realm); } finally { delete manager; } } public static void DeleteAllProtocolMappings(CredentialsManagerContract.Imp! manager) { manager.SendDeleteAllProtocolMappings(); switch receive { case manager.Ok(): break; case manager.RequestFailed(CredError error): throw new CredentialsManagerException("The request to delete all protocol mappings failed.", error); } } public static void DeleteAllProtocolMappings() { CredentialsManagerContract.Imp! manager = ConnectService(); try { DeleteAllProtocolMappings(manager); } finally { delete manager; } } public static bool FindMatchingProtocolMapping( CredentialsManagerContract.Imp! manager, string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, bool useWildcard, out string! credentialsName, out string! tag) { ProtocolTuple tuple = new ProtocolTuple(); tuple.ApplicationProtocol = Bitter.FromString2(applicationProtocol); tuple.ServiceAddress = Bitter.FromString2(serviceAddress); tuple.AuthenticationProtocol = Bitter.FromString2(authenticationProtocol); tuple.Realm = Bitter.FromString2(realm); manager.SendFindMatchingProtocolMapping(tuple, useWildcard); switch receive { case manager.NoMatchingProtocolMapping(): credentialsName = ""; tag = ""; return false; case manager.MatchingProtocolMapping(CredentialsId credentials): credentialsName = Bitter.ToString2(credentials.CredentialsName); tag = Bitter.ToString2(credentials.Tag); credentials.Dispose(); return true; case manager.RequestFailed(error): throw new CredentialsManagerException("The request to find a protocol mapping failed.", error); } } public static bool FindMatchingProtocolMapping( string! applicationProtocol, string! serviceAddress, string! authenticationProtocol, string! realm, bool useWildcard, out string! credentialsName, out string! tag) { CredentialsManagerContract.Imp! manager = ConnectService(); try { return FindMatchingProtocolMapping( manager, applicationProtocol, serviceAddress, authenticationProtocol, realm, useWildcard, out credentialsName, out tag); } finally { delete manager; } } const string! ChannelClosedMsg = "The request failed because the Credentials Manager service closed the control channel."; } public class CredentialsManagerException : Exception { public CredentialsManagerException(CredError error) { string! msg = CredentialsManager.CredErrorToString(error); base(msg); } public CredentialsManagerException(string! msg, CredError error) { string! errorText = CredentialsManager.CredErrorToString(error); base(msg + " Error: " + errorText); } public CredentialsManagerException(string! msg) { base(msg); } } }