public async Task Rotate(IActiveDirectoryApplication application, string keyName = null, int keyDurationInMinutes = 0) { _keyVaultService.Log = Log; _applicationService.Log = Log; if (string.IsNullOrWhiteSpace(keyName)) { keyName = Environment.GetEnvironmentVariable("DefaultKeyName", EnvironmentVariableTarget.Process); Log.LogDebug($"No custom keyname so use default keyname '{keyName}'"); } var allSecrets = await _keyVaultService.GetAllSecretsFromKeyVault(); var secret = GetSecretByApplicationObjectId(allSecrets, application.Id); if (secret == null) { Log.LogWarning($"No secret found in the KeyVault that belongs by the application with ObjectId '{application.Id}'. Key rotation for this application will be skipped. Add a secret to the KeyVault for this application to start key rotation."); } else { string key = SecretHelper.GenerateSecretKey(); await _applicationService.AddSecretToActiveDirectoryApplication(application, keyName, key, keyDurationInMinutes); await _keyVaultService.SetSecret(secret, key, secret.Tags); } await _applicationService.RemoveExpiredKeys(application); }
/** * Azure Service Principal sample for managing Service Principal - * - Create an Active Directory application * - Create a Service Principal for the application and assign a role * - Export the Service Principal to an authentication file * - Use the file to list subcription virtual machines * - Update the application * - Update the service principal to revoke the password credential and the role * - Delete the Service Principal. */ public static void RunSample(Azure.IAuthenticated authenticated) { string subscriptionId = authenticated.Subscriptions.List().First <ISubscription>().SubscriptionId; Utilities.Log("Selected subscription: " + subscriptionId); IActiveDirectoryApplication activeDirectoryApplication = null; string authFilePath = Path.Combine(Utilities.ProjectPath, "Asset", "mySamplAuthdFile.azureauth").ToString(); try { activeDirectoryApplication = CreateActiveDirectoryApplication(authenticated); IServicePrincipal servicePrincipal = CreateServicePrincipalWithRoleForApplicationAndExportToFile(authenticated, activeDirectoryApplication, BuiltInRole.Contributor, subscriptionId, authFilePath); // Wait until Service Principal is ready SdkContext.DelayProvider.Delay(15); UseAuthFile(authFilePath); UpdateApplication(authenticated, activeDirectoryApplication); UpdateServicePrincipal(authenticated, servicePrincipal); } finally { Utilities.Log("Deleting Active Directory application and Service Principal..."); if (activeDirectoryApplication != null) { // this will delete Service Principal as well authenticated.ActiveDirectoryApplications.DeleteById(activeDirectoryApplication.Id); } } }
private static IServicePrincipal CreateServicePrincipalWithRoleForApplicationAndExportToFile( Azure.IAuthenticated authenticated, IActiveDirectoryApplication activeDirectoryApplication, BuiltInRole role, string subscriptionId, string authFilePath) { Utilities.Log("Creating Service Principal..."); string name = SdkContext.RandomResourceName("sp-sample", 20); //create a self-sighed certificate string domainName = name + ".com"; string certPassword = Utilities.CreatePassword(); Certificate certificate = Certificate.CreateSelfSigned(domainName, certPassword); // create a Service Principal and assign it to a subscription with the role Contributor return(authenticated.ServicePrincipals .Define("name") .WithExistingApplication(activeDirectoryApplication) // password credentials definition .DefinePasswordCredential("ServicePrincipalAzureSample") .WithPasswordValue(Utilities.CreatePassword()) .Attach() // certificate credentials definition .DefineCertificateCredential("spcert") .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes(certificate.CerPath)) .WithDuration(TimeSpan.FromDays(7)) // export the credentials to the file .WithAuthFileToExport(new StreamWriter(new FileStream(authFilePath, FileMode.OpenOrCreate))) .WithPrivateKeyFile(certificate.PfxPath) .WithPrivateKeyPassword(certPassword) .Attach() .WithNewRoleInSubscription(role, subscriptionId) .Create()); }
public void CanCRUDApplication() { using (var context = FluentMockContext.Start(GetType().FullName)) { IGraphRbacManager manager = TestHelper.CreateGraphRbacManager(); String name = SdkContext.RandomResourceName("javasdkapp", 20); IActiveDirectoryApplication application = null; try { application = manager.Applications.Define(name) .WithSignOnUrl("http://easycreate.azure.com/" + name) .DefinePasswordCredential("passwd") .WithPasswordValue("P@ssw0rd") .WithDuration(TimeSpan.FromDays(100)) .Attach() .DefineCertificateCredential("cert") .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes("Assets/myTest.cer")) .WithDuration(TimeSpan.FromDays(100)) .Attach() .DefineCertificateCredential("cert") .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes("Assets/myTest2.cer")) .WithDuration(TimeSpan.FromDays(80)) .Attach() .Create(); Console.WriteLine(application.Id + " - " + application.ApplicationId); Assert.NotNull(application.Id); Assert.NotNull(application.ApplicationId); Assert.Equal(name, application.Name); Assert.Equal(2, application.CertificateCredentials.Count); Assert.Equal(1, application.PasswordCredentials.Count); Assert.Equal(1, application.ReplyUrls.Count); Assert.Equal(1, application.IdentifierUris.Count); Assert.Equal("http://easycreate.azure.com/" + name, application.SignOnUrl.ToString()); application.Update() .WithoutCredential("passwd") .Apply(); Console.WriteLine(application.Id + " - " + application.ApplicationId); Assert.Equal(0, application.PasswordCredentials.Count); } finally { if (application != null) { manager.Applications.DeleteById(application.Id); } } } }
private static void UpdateApplication(Azure.IAuthenticated authenticated, IActiveDirectoryApplication activeDirectoryApplication) { Utilities.Log("Updating Active Directory application..."); activeDirectoryApplication.Update() // add another password credentials .DefinePasswordCredential("password-1") .WithPasswordValue("P@ssw0rd-1") .WithDuration(TimeSpan.FromDays(700)) .Attach() // add a reply url .WithReplyUrl("http://localhost:8080") .Apply(); }
private string GetAvailableKeyName(IActiveDirectoryApplication application, string keyName, int suffixNumber) { string completeKeyName = keyName + suffixNumber; var existingKeyNames = application.PasswordCredentials.Values.Select(p => p.Name); if (!existingKeyNames.Contains(completeKeyName)) { return(completeKeyName); } else { suffixNumber++; return(GetAvailableKeyName(application, keyName, suffixNumber)); } }
public override async Task <Microsoft.Azure.Management.Graph.RBAC.Fluent.IServicePrincipal> CreateResourceAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (IsInCreateMode()) { if (applicationCreatable != null) { IActiveDirectoryApplication application = (IActiveDirectoryApplication)base.CreatedResource(applicationCreatable.Key); createParameters.AppId = application.ApplicationId; } ServicePrincipalInner inner = await manager.Inner.ServicePrincipals.CreateAsync(createParameters, cancellationToken); SetInner(inner); } Task.WaitAll( SubmitCredentialsAsync(this, cancellationToken), SubmitRolesAsync(this, cancellationToken)); foreach (IPasswordCredential password in passwordCredentialsToCreate) { if (password is PasswordCredentialImpl <IWithCreate> ) { await((PasswordCredentialImpl <IWithCreate>)password).ExportAuthFileAsync(this, cancellationToken); } else { await((PasswordCredentialImpl <IUpdate>)password).ExportAuthFileAsync(this, cancellationToken); } } foreach (ICertificateCredential certificate in certificateCredentialsToCreate) { if (certificate is CertificateCredentialImpl <IWithCreate> ) { await((CertificateCredentialImpl <IWithCreate>)certificate).ExportAuthFileAsync(this, cancellationToken); } else { await((CertificateCredentialImpl <IUpdate>)certificate).ExportAuthFileAsync(this, cancellationToken); } } passwordCredentialsToCreate.Clear(); certificateCredentialsToCreate.Clear(); return(await RefreshCredentialsAsync(cancellationToken)); }
public async Task RemoveExpiredKeys(IActiveDirectoryApplication application) { Log.LogDebug($"Remove expired keys of application with Id '{application.Id}'"); try { var expiredCredentials = application .PasswordCredentials .Where(s => s.Value.EndDate < DateTime.UtcNow) .ToList(); if (expiredCredentials.Any()) { foreach (var expiredCredential in expiredCredentials) { string keyName = expiredCredential.Value.Name; await application .Update() .WithoutCredential(keyName) .ApplyAsync(); Log.LogInformation($"Removed the expired key '{keyName}' of application with id '{application.Id}'"); } } else { Log.LogInformation($"No expired keys to remove for application with id '{application.Id}'"); } Log.LogDebug($"Removed all expired keys of application with id '{application.Id}'"); } catch (GraphErrorException ex) { if (ex.Response.StatusCode == HttpStatusCode.Forbidden) { Log.LogError($"Forbidden to remove expired keys of active directory application with id '{application.Id}'"); Log.LogDebug($"Extra info for application with id '{application.Id}': '{ex.Response.Content}'."); } else { Log.LogError(ex.Response.Content); } } }
public async Task AddSecretToActiveDirectoryApplication(IActiveDirectoryApplication application, string keyName, string key, int keyDurationInMinutes) { Log.LogDebug($"Add new secret to application with Id '{application.Id}'"); string availableKeyName = GetAvailableKeyName(application, keyName, 1); if (keyDurationInMinutes < 1) { keyDurationInMinutes = Convert.ToInt32(Environment.GetEnvironmentVariable("KeyDurationInMinutes", EnvironmentVariableTarget.Process)); Log.LogDebug($"No custom keyduration so use default keyduration of '{keyName}' minutes"); } var duration = new TimeSpan(0, keyDurationInMinutes, 0); DateTime utcNow = DateTime.UtcNow; try { await application .Update() .DefinePasswordCredential(availableKeyName) .WithPasswordValue(key) .WithStartDate(utcNow) .WithDuration(duration) .Attach() .ApplyAsync(); Log.LogInformation($"Added new key with name '{availableKeyName}' to application with id '{application.Id}' that is valid from UTC '{utcNow}' with a duraction of '{keyDurationInMinutes}' minutes"); } catch (GraphErrorException ex) { if (ex.Response.StatusCode == HttpStatusCode.Forbidden) { Log.LogError($"Forbidden to set key for active directory application with id '{application.Id}'"); Log.LogDebug($"Extra info for application with id '{application.Id}': '{ex.Response.Content}'."); } else { Log.LogError(ex.Response.Content); } } }
internal async Task Rotate(IActiveDirectoryApplication application, string keyName) { var secrets = await GetAllSecretsFromKeyVault(); var secret = GetSecretByApplicationObjectId(application.Id, secrets); if (secret == null) { _log.Error($"No secret found in the KeyVault that belongs by the application with ObjectId '{application.Id}'. Key rotation for this application will be skipped. Add a secret to the KeyVault for this application to start key rotation."); } else { string key = GenerateSecretKey(); await AddSecretToActiveDirectoryApplication(application, keyName, key); var tags = secret.Tags; _log.Verbose($"Set new value for secret '{secret.Identifier.Name}' in KeyVault"); await _keyVaultClient.SetSecretAsync(_keyVaultUrl, secret.Identifier.Name, key, tags); _log.Info($"Updated the secret '{secret.Identifier.Name}' with a new value in the KeyVault"); } }
private async Task AddSecretToActiveDirectoryApplication(IActiveDirectoryApplication application, string keyName, string key) { _log.Verbose($"Add new secret to application with Id '{application.Id}'"); string availableKeyName = GetAvailableKeyName(application, keyName, 1); int keyDurationInMinutes = 5; var duration = new TimeSpan(0, keyDurationInMinutes, 0); DateTime utcNow = DateTime.UtcNow; try { // Remove all existing keys... https://github.com/Azure/azure-libraries-for-net/issues/414 await application .Update() .DefinePasswordCredential(availableKeyName) .WithPasswordValue(key) .WithStartDate(utcNow) .WithDuration(duration) .Attach() .ApplyAsync(); _log.Info($"Added new key with name '{availableKeyName}' to application with id '{application.Id}' that is valid from UTC '{utcNow}' with a duraction of '{keyDurationInMinutes}' minutes"); } catch (GraphErrorException ex) { if (ex.Response.StatusCode == HttpStatusCode.Forbidden) { _log.Error($"Forbidden to set key for active directory application with id '{application.Id}'"); _log.Verbose($"Extra info for application with id '{application.Id}': '{ex.Response.Content}'."); } else { _log.Error(ex.Response.Content); } } }
public ServicePrincipalImpl WithExistingApplication(IActiveDirectoryApplication application) { createParameters.AppId = application.ApplicationId; return(this); }
internal async Task Rotate(IActiveDirectoryApplication application, string keyName) { string key = GenerateSecretKey(); await AddSecretToActiveDirectoryApplication(application, keyName, key); }
/// <summary> /// Specifies an existing application to use by the service principal. /// </summary> /// <param name="application">The application.</param> /// <return>The next stage of the service principal definition.</return> ServicePrincipal.Definition.IWithCreate ServicePrincipal.Definition.IWithApplicationBeta.WithExistingApplication(IActiveDirectoryApplication application) { return(this.WithExistingApplication(application) as ServicePrincipal.Definition.IWithCreate); }
public void CanCRUDApplication() { using (var context = FluentMockContext.Start(GetType().FullName)) { IGraphRbacManager manager = TestHelper.CreateGraphRbacManager(); String name = SdkContext.RandomResourceName("javasdkapp", 20); IActiveDirectoryApplication application = null; try { application = manager.Applications.Define(name) .WithSignOnUrl("http://easycreate.azure.com/" + name) .DefinePasswordCredential("passwd") .WithPasswordValue("P@ssw0rd") .WithDuration(TimeSpan.FromDays(100)) .Attach() .DefineCertificateCredential("cert") .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes("Assets/myTest.cer")) .WithDuration(TimeSpan.FromDays(100)) .Attach() .DefineCertificateCredential() .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes("Assets/myTest2.cer")) .WithDuration(TimeSpan.FromDays(80)) .Attach() .Create(); Console.WriteLine(application.Id + " - " + application.ApplicationId); Assert.NotNull(application.Id); Assert.NotNull(application.ApplicationId); Assert.Equal(name, application.Name); Assert.Equal(2, application.CertificateCredentials.Count); Assert.Equal(1, application.PasswordCredentials.Count); Assert.Equal(1, application.ReplyUrls.Count); Assert.Equal(1, application.IdentifierUris.Count); Assert.Equal("http://easycreate.azure.com/" + name, application.SignOnUrl.ToString()); // check thumbprint, the customKeyIdentifier would be thumbprint if not set var certificate = new X509Certificate("Assets/myTest2.cer"); var certificateCount = 0; foreach (var certificateCredential in application.CertificateCredentials.Values) { if (certificateCredential.Name != "cert") { certificateCount++; Assert.Equal(certificate.GetCertHashString(), certificateCredential.CustomKeyIdentifier); } } Assert.True(certificateCount > 0); application.Update() .DefinePasswordCredential("passwd2") .WithPasswordValue("StrongPass!12") .WithDuration(TimeSpan.FromDays(20)) .Attach() .DefineCertificateCredential("cert") .WithAsymmetricX509Certificate() .WithPublicKey(File.ReadAllBytes("Assets/myTest2.cer")) .WithDuration(TimeSpan.FromDays(1)) .Attach() .WithoutCredentialByIdentifier(certificate.GetCertHashString()) .Apply(); Console.WriteLine(application.Id + " - " + application.ApplicationId); Assert.Equal(2, application.PasswordCredentials.Count); Assert.Equal(2, application.CertificateCredentials.Count); application.Update() .WithoutCredential("passwd") .Apply(); Console.WriteLine(application.Id + " - " + application.ApplicationId); Assert.Equal(1, application.PasswordCredentials.Count); Assert.Equal("passwd2", application.PasswordCredentials.First().Value.Name); } finally { if (application != null) { manager.Applications.DeleteById(application.Id); } } } }