Example #1
0
        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));
        }
Example #8
0
        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);
                }
            }
        }
Example #9
0
        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);
                }
            }
        }
Example #10
0
        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);
                    }
                }
            }
        }