com.azure.resourcemanager.authorization.implementation.ServicePrincipalImpl Maven / Gradle / Ivy
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.resourcemanager.authorization.implementation;
import com.azure.resourcemanager.authorization.AuthorizationManager;
import com.azure.resourcemanager.authorization.fluent.models.MicrosoftGraphPasswordCredentialInner;
import com.azure.resourcemanager.authorization.fluent.models.MicrosoftGraphServicePrincipalInner;
import com.azure.resourcemanager.authorization.fluent.models.ServicePrincipalsAddPasswordRequestBodyInner;
import com.azure.resourcemanager.authorization.models.ActiveDirectoryApplication;
import com.azure.resourcemanager.authorization.models.BuiltInRole;
import com.azure.resourcemanager.authorization.models.CertificateCredential;
import com.azure.resourcemanager.authorization.models.PasswordCredential;
import com.azure.resourcemanager.authorization.models.RoleAssignment;
import com.azure.resourcemanager.authorization.models.ServicePrincipal;
import com.azure.resourcemanager.resources.fluentcore.model.Creatable;
import com.azure.resourcemanager.resources.fluentcore.model.implementation.CreatableUpdatableImpl;
import com.azure.resourcemanager.resources.models.ResourceGroup;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.retry.Retry;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Implementation for ServicePrincipal and its parent interfaces. */
class ServicePrincipalImpl
extends CreatableUpdatableImpl
implements ServicePrincipal,
ServicePrincipal.Definition,
ServicePrincipal.Update,
HasCredential {
private AuthorizationManager manager;
private Map cachedPasswordCredentials;
private Map cachedCertificateCredentials;
private Map cachedRoleAssignments;
private Creatable applicationCreatable;
private Map rolesToCreate;
private Set rolesToDelete;
String assignedSubscription;
private List> certificateCredentialsToCreate;
private List> passwordCredentialsToCreate;
ServicePrincipalImpl(MicrosoftGraphServicePrincipalInner innerObject, AuthorizationManager manager) {
super(innerObject.displayName(), innerObject);
this.manager = manager;
this.cachedRoleAssignments = new HashMap<>();
this.rolesToCreate = new HashMap<>();
this.rolesToDelete = new HashSet<>();
this.cachedCertificateCredentials = new HashMap<>();
this.certificateCredentialsToCreate = new ArrayList<>();
this.cachedPasswordCredentials = new HashMap<>();
this.passwordCredentialsToCreate = new ArrayList<>();
this.refreshCredentials(innerObject);
}
@Override
public String applicationId() {
return innerModel().appId();
}
@Override
public List servicePrincipalNames() {
return innerModel().servicePrincipalNames();
}
@Override
public Map passwordCredentials() {
return Collections.unmodifiableMap(cachedPasswordCredentials);
}
@Override
public Map certificateCredentials() {
return Collections.unmodifiableMap(cachedCertificateCredentials);
}
@Override
public Set roleAssignments() {
return Collections.unmodifiableSet(new HashSet<>(cachedRoleAssignments.values()));
}
@Override
protected Mono getInnerAsync() {
return manager.serviceClient().getServicePrincipalsServicePrincipals().getServicePrincipalAsync(id())
.doOnSuccess(this::refreshCredentials);
}
@Override
public Mono createResourceAsync() {
Retry retry = isInCreateMode() ? RetryUtils.backoffRetryFor404ResourceNotFound() : null;
Mono sp;
if (isInCreateMode()) {
innerModel().withAccountEnabled(true);
if (applicationCreatable != null) {
ActiveDirectoryApplication application = this.taskResult(applicationCreatable.key());
innerModel().withAppId(application.applicationId());
}
sp = manager.serviceClient().getServicePrincipalsServicePrincipals()
.createServicePrincipalAsync(innerModel()).map(innerToFluentMap(this));
if (applicationCreatable != null) {
// retry on 400, if app is created with "withNewApplication"
sp = sp.retryWhen(RetryUtils.backoffRetryFor400BadRequest());
}
} else {
sp = manager().serviceClient().getServicePrincipalsServicePrincipals()
.updateServicePrincipalAsync(id(), new MicrosoftGraphServicePrincipalInner()
.withKeyCredentials(innerModel().keyCredentials())
.withPasswordCredentials(innerModel().passwordCredentials())
).then(refreshAsync());
}
return sp
.flatMap(
servicePrincipal ->
submitCredentialsAsync(servicePrincipal, retry)
// retry for Microsoft.Authorization is done in RoleAssignmentImpl
.mergeWith(submitRolesAsync(servicePrincipal))
.last())
.map(
servicePrincipal -> {
for (PasswordCredentialImpl> passwordCredential : passwordCredentialsToCreate) {
passwordCredential.exportAuthFile((ServicePrincipalImpl) servicePrincipal);
passwordCredential.consumeSecret();
}
for (CertificateCredentialImpl> certificateCredential : certificateCredentialsToCreate) {
certificateCredential.exportAuthFile((ServicePrincipalImpl) servicePrincipal);
}
passwordCredentialsToCreate.clear();
certificateCredentialsToCreate.clear();
return servicePrincipal;
});
}
private Mono submitCredentialsAsync(final ServicePrincipal servicePrincipal, Retry retry) {
return Flux.defer(() ->
// Flux.fromIterable(certificateCredentialsToCreate)
// .flatMap(certificateCredential ->
// manager().serviceClient().getServicePrincipals()
// .addKeyAsync(id(),
// new ServicePrincipalsAddKeyRequestBodyInner()
// .withKeyCredential(certificateCredential.innerModel()))),
// Flux.fromIterable(certificateCredentialsToDelete)
// .flatMap(id -> manager().serviceClient().getServicePrincipals()
// .removeKeyAsync(id(),
// new ServicePrincipalsRemoveKeyRequestBody()
// .withKeyId(UUID.fromString(id)))),
Flux.fromIterable(passwordCredentialsToCreate)
.flatMap(passwordCredential -> {
Mono monoAddPassword =
manager().serviceClient().getServicePrincipals()
.addPasswordAsync(id(),
new ServicePrincipalsAddPasswordRequestBodyInner()
.withPasswordCredential(passwordCredential.innerModel()));
if (retry != null) {
monoAddPassword = monoAddPassword.retryWhen(retry);
}
monoAddPassword = monoAddPassword.doOnNext(passwordCredential::setInner);
return monoAddPassword;
})
// Flux.fromIterable(passwordCredentialsToDelete)
// .flatMap(id -> manager().serviceClient().getServicePrincipals()
// .removePasswordAsync(id(),
// new ServicePrincipalsRemovePasswordRequestBody()
// .withKeyId(UUID.fromString(id))))
)
.then(Mono.defer(() -> {
Mono monoRefresh = refreshAsync();
if (retry != null) {
monoRefresh = monoRefresh.retryWhen(retry);
}
return monoRefresh;
}));
}
private Mono submitRolesAsync(final ServicePrincipal servicePrincipal) {
Mono create;
if (rolesToCreate.isEmpty()) {
create = Mono.just(servicePrincipal);
} else {
create =
Flux
.fromIterable(rolesToCreate.entrySet())
.flatMap(roleEntry -> manager()
.roleAssignments()
.define(this.manager().internalContext().randomUuid())
.forServicePrincipal(servicePrincipal)
.withBuiltInRole(roleEntry.getValue())
.withScope(roleEntry.getKey())
.createAsync())
.doOnNext(
indexable ->
cachedRoleAssignments.put(indexable.id(), indexable))
.last()
.map(
indexable -> {
rolesToCreate.clear();
return servicePrincipal;
});
}
Mono delete;
if (rolesToDelete.isEmpty()) {
delete = Mono.just(servicePrincipal);
} else {
delete =
Flux
.fromIterable(rolesToDelete)
.flatMap(
role ->
manager()
.roleAssignments()
.deleteByIdAsync(cachedRoleAssignments.get(role).id())
.thenReturn(role))
.doOnNext(s -> cachedRoleAssignments.remove(s))
.last()
.map(
s -> {
rolesToDelete.clear();
return servicePrincipal;
});
}
return create.mergeWith(delete).last();
}
@Override
public boolean isInCreateMode() {
return id() == null;
}
void refreshCredentials(MicrosoftGraphServicePrincipalInner inner) {
cachedCertificateCredentials.clear();
cachedPasswordCredentials.clear();
if (inner.keyCredentials() != null) {
inner.keyCredentials().forEach(keyCredentialInner -> {
CertificateCredential certificateCredential = new CertificateCredentialImpl<>(keyCredentialInner);
cachedCertificateCredentials.put(certificateCredential.name(), certificateCredential);
});
}
if (inner.passwordCredentials() != null) {
inner.passwordCredentials().forEach(passwordCredentialInner -> {
PasswordCredential passwordCredential = new PasswordCredentialImpl<>(passwordCredentialInner);
cachedPasswordCredentials.put(passwordCredential.name(), passwordCredential);
});
}
}
@Override
public Mono refreshAsync() {
return getInnerAsync().map(innerToFluentMap(this));
}
@Override
public CertificateCredentialImpl defineCertificateCredential(String name) {
return new CertificateCredentialImpl<>(name, this);
}
@Override
public PasswordCredentialImpl definePasswordCredential(String name) {
return new PasswordCredentialImpl<>(name, this);
}
@Override
public ServicePrincipalImpl withoutCredential(String name) {
if (cachedPasswordCredentials.containsKey(name)) {
innerModel().passwordCredentials().remove(cachedPasswordCredentials.get(name).innerModel());
} else if (cachedCertificateCredentials.containsKey(name)) {
innerModel().keyCredentials().remove(cachedCertificateCredentials.get(name).innerModel());
}
return this;
}
@Override
public ServicePrincipalImpl withCertificateCredential(CertificateCredentialImpl> credential) {
this.certificateCredentialsToCreate.add(credential);
if (innerModel().keyCredentials() == null) {
innerModel().withKeyCredentials(new ArrayList<>());
}
innerModel().keyCredentials().add(credential.innerModel());
return this;
}
@Override
public ServicePrincipalImpl withPasswordCredential(PasswordCredentialImpl> credential) {
this.passwordCredentialsToCreate.add(credential);
return this;
}
@Override
public ServicePrincipalImpl withExistingApplication(String id) {
innerModel().withAppId(id);
return this;
}
@Override
public ServicePrincipalImpl withExistingApplication(ActiveDirectoryApplication application) {
innerModel().withAppId(application.applicationId());
return this;
}
@Override
public ServicePrincipalImpl withNewApplication(Creatable applicationCreatable) {
this.addDependency(applicationCreatable);
this.applicationCreatable = applicationCreatable;
return this;
}
@Override
public ServicePrincipalImpl withNewApplication(String signOnUrl) {
return withNewApplication(
manager.applications().define(name()).withSignOnUrl(signOnUrl).withIdentifierUrl(signOnUrl));
}
@Override
public ServicePrincipalImpl withNewApplication() {
return withNewApplication(
manager.applications().define(name()));
}
@Override
public ServicePrincipalImpl withNewRole(BuiltInRole role, String scope) {
this.rolesToCreate.put(scope, role);
return this;
}
@Override
public ServicePrincipalImpl withNewRoleInSubscription(BuiltInRole role, String subscriptionId) {
this.assignedSubscription = subscriptionId;
return withNewRole(role, "subscriptions/" + subscriptionId);
}
@Override
public ServicePrincipalImpl withNewRoleInResourceGroup(BuiltInRole role, ResourceGroup resourceGroup) {
return withNewRole(role, resourceGroup.id());
}
@Override
public Update withoutRole(RoleAssignment roleAssignment) {
this.rolesToDelete.add(roleAssignment.id());
return this;
}
@Override
public String id() {
return innerModel().id();
}
@Override
public AuthorizationManager manager() {
return this.manager;
}
}