Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.intellij.ui.EditorTextField;
import com.intellij.ui.EditorTextFieldProvider;
import com.intellij.ui.SoftWrapsEditorCustomization;
import com.intellij.util.ui.UIUtil;
import com.microsoft.azure.toolkit.intellij.common.AzureCommentLabel;
import com.microsoft.azure.toolkit.intellij.common.AzureDialog;
import com.microsoft.azure.toolkit.intellij.common.TextDocumentListenerAdapter;
Expand Down Expand Up @@ -61,6 +60,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
Expand All @@ -78,9 +78,8 @@ public class ServicePrincipalLoginDialog extends AzureDialog<AuthConfiguration>
private TextFieldWithBrowseButton certFileTextField;
private AzureCommentLabel comment;
private final Project project;
private boolean intermediateState = false;
private AuthConfiguration auth = new AuthConfiguration();

private AtomicBoolean intermediateState = new AtomicBoolean(false);

protected ServicePrincipalLoginDialog(@Nonnull Project project) {
super(project);
Expand Down Expand Up @@ -256,33 +255,40 @@ public static String findTextInClipboard(Predicate<String> func) {
}

private void uiTextComponents2Json() {
if (intermediateState) {
if (!intermediateState.compareAndSet(false, true)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned in daily scrum.
you can solve the problem in a more elegant way by comparing the data-model(but not the view model) of the upper inputs-form and lower json-form, and then sync to the other when one is changed.

return;
}
Map<String, String> map = new LinkedHashMap<>();
AuthConfiguration data = getData();

if (this.certificateRadioButton.isSelected()) {
map.put("fileWithCertAndPrivateKey", data.getCertificate());
} else {
String password = StringUtils.isNotBlank(data.getKey()) ? "<hidden>" : "<empty>";
map.put("password", password);
}
map.put("appId", data.getClient());
map.put("tenant", data.getTenant());
String text = JsonUtils.getGson().toJson(map);
if (!StringUtils.equals(jsonDataEditor.getText(), text)) {
this.jsonDataEditor.setText(text);
this.jsonDataEditor.setCaretPosition(0);
try {
Map<String, String> map = new LinkedHashMap<>();
AuthConfiguration data = getData();

if (this.certificateRadioButton.isSelected()) {
map.put("fileWithCertAndPrivateKey", data.getCertificate());
} else {
String password = StringUtils.isNotBlank(data.getKey()) ? "<hidden>" : "<empty>";
map.put("password", password);
}
map.put("appId", data.getClient());
map.put("tenant", data.getTenant());
String text = JsonUtils.getGson().toJson(map);
if (!StringUtils.equals(jsonDataEditor.getText(), text)) {
this.jsonDataEditor.setText(text);
this.jsonDataEditor.setCaretPosition(0);
}
} finally {
intermediateState.set(false);
}
}

private void json2UIComponents(String json) {
try {
Map<String, String> map = JsonUtils.fromJson(json, HashMap.class);
if (map != null) {
UIUtil.invokeLaterIfNeeded(() -> {
intermediateState = true;
ApplicationManager.getApplication().invokeAndWait(() -> {
if (!intermediateState.compareAndSet(false, true)) {
return;
}

try {
if (map.containsKey("appId")) {
this.clientIdTextField.setText(StringUtils.defaultString(map.get("appId")));
Expand All @@ -302,7 +308,7 @@ private void json2UIComponents(String json) {
this.certFileTextField.setText(StringUtils.defaultString(map.get("fileWithCertAndPrivateKey")));
}
} finally {
intermediateState = false;
intermediateState.set(false);
}

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.AnimatedIcon;
import com.intellij.util.ui.UIUtil;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
Expand All @@ -27,10 +26,15 @@
import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
import com.microsoft.azuretools.adauth.IDeviceLoginUI;
import com.microsoft.azuretools.authmanage.*;
import com.microsoft.azuretools.authmanage.AuthMethod;
import com.microsoft.azuretools.authmanage.AuthMethodManager;
import com.microsoft.azuretools.authmanage.CommonSettings;
import com.microsoft.azuretools.authmanage.models.AuthMethodDetails;
import com.microsoft.azuretools.sdkmanage.IdentityAzureManager;
import com.microsoft.azuretools.telemetrywrapper.*;
import com.microsoft.azuretools.telemetrywrapper.ErrorType;
import com.microsoft.azuretools.telemetrywrapper.EventUtil;
import com.microsoft.azuretools.telemetrywrapper.Operation;
import com.microsoft.azuretools.telemetrywrapper.TelemetryManager;
import com.microsoft.intellij.secure.IdeaSecureStore;
import com.microsoft.intellij.ui.components.AzureDialogWrapper;
import org.apache.commons.collections4.CollectionUtils;
Expand All @@ -43,17 +47,27 @@
import reactor.util.function.Tuple2;
import rx.Single;

import javax.swing.*;
import java.awt.*;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import java.awt.Component;
import java.net.URI;
import java.time.Duration;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;

import static com.microsoft.azuretools.telemetry.TelemetryConstants.*;
import static com.microsoft.azuretools.telemetry.TelemetryConstants.ACCOUNT;
import static com.microsoft.azuretools.telemetry.TelemetryConstants.AZURE_ENVIRONMENT;
import static com.microsoft.azuretools.telemetry.TelemetryConstants.SIGNIN;
import static com.microsoft.azuretools.telemetry.TelemetryConstants.SIGNIN_METHOD;

public class SignInWindow extends AzureDialogWrapper {
private static final Logger LOGGER = Logger.getInstance(SignInWindow.class);
Expand All @@ -71,7 +85,6 @@ public class SignInWindow extends AzureDialogWrapper {
private JLabel labelOAuthLogin;

private AuthMethodDetails authMethodDetails;
private AuthMethodDetails authMethodDetailsResult;

private String accountEmail;

Expand Down Expand Up @@ -112,10 +125,6 @@ public SignInWindow(AuthMethodDetails authMethodDetails, Project project) {
checkAccountAvailability();
}

public AuthMethodDetails getAuthMethodDetails() {
return authMethodDetailsResult;
}

@Nullable
public static SignInWindow go(AuthMethodDetails authMethodDetails, Project project) {
SignInWindow signInWindow = new SignInWindow(authMethodDetails, project);
Expand All @@ -127,12 +136,6 @@ public static SignInWindow go(AuthMethodDetails authMethodDetails, Project proje
return null;
}

@Override
public void doCancelAction() {
authMethodDetailsResult = authMethodDetails;
super.doCancelAction();
}

@Override
public void doHelpAction() {
final JXHyperlink helpLink = new JXHyperlink();
Expand All @@ -153,43 +156,55 @@ protected JComponent createCenterPanel() {
}

public Single<AuthMethodDetails> login() {
AuthConfiguration auth = new AuthConfiguration();
if (spRadioButton.isSelected()) {
final ServicePrincipalLoginDialog dialog = new ServicePrincipalLoginDialog(project);
if (dialog.showAndGet()) {
auth = dialog.getData();
}
} else if (deviceLoginRadioButton.isSelected()) {
auth.setType(AuthType.DEVICE_CODE);
} else if (oauthLoginRadioButton.isSelected()) {
auth.setType(AuthType.OAUTH2);
} else if (azureCliRadioButton.isSelected()) {
auth.setType(AuthType.AZURE_CLI);
}
return loginAsync(auth);
}

private Single<AuthMethodDetails> loginAsync(AuthConfiguration auth) {
final IAzureOperationTitle title = AzureOperationBundle.title("account.sign_in");
final AzureTask<AuthMethodDetails> task = new AzureTask<>(null, title, true, () -> {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
indicator.setIndeterminate(true);
return this.doLogin(indicator);
return doLogin(indicator, auth);
});
return AzureTaskManager.getInstance().runInModalAsObservable(task).toSingle();
}

private @Nullable AuthMethodDetails doLogin(ProgressIndicator indicator) {
authMethodDetailsResult = new AuthMethodDetails();
if (spRadioButton.isSelected()) { // automated
final Map<String, String> properties = new HashMap<>();
properties.put(AZURE_ENVIRONMENT, CommonSettings.getEnvironment().getName());
properties.putAll(signInSPProp);
EventUtil.logEvent(EventType.info, ACCOUNT, SIGNIN, properties, null);

UIUtil.invokeAndWaitIfNeeded(() -> call(this::doServicePrincipalLogin, "sp"));
} else if (deviceLoginRadioButton.isSelected()) {
authMethodDetailsResult = call(this::doDeviceLogin, "dc");
} else if (azureCliRadioButton.isSelected()) {
authMethodDetailsResult = call(() -> checkCanceled(indicator, IdentityAzureManager.getInstance().signInAzureCli()), "az");
} else if (oauthLoginRadioButton.isSelected()) {
authMethodDetailsResult = call(() -> checkCanceled(indicator, IdentityAzureManager.getInstance().signInOAuth()), "oauth");
public AuthMethodDetails doLogin(ProgressIndicator indicator, AuthConfiguration auth) {
AuthMethodDetails authMethodDetailsResult = new AuthMethodDetails();
if (AuthMethodManager.getInstance().isSignedIn()) {
doSignOut();
}
return authMethodDetailsResult;
}

private AuthMethodDetails doServicePrincipalLogin() {
authMethodDetailsResult = new AuthMethodDetails();
final ServicePrincipalLoginDialog dialog = new ServicePrincipalLoginDialog(project);
if (dialog.showAndGet()) {
AuthConfiguration data = dialog.getData();
authMethodDetailsResult = doServicePrincipalLoginInternal(data);
if (StringUtils.isNotBlank(data.getKey())) {
secureStore.savePassword(StringUtils.joinWith("|", "account", data.getClient()), data.getKey());
}
switch (auth.getType()) {
case SERVICE_PRINCIPAL:
authMethodDetailsResult = call(() -> checkCanceled(indicator, IdentityAzureManager.getInstance().signInServicePrincipal(auth)), "sp");
if (StringUtils.isNotBlank(auth.getKey())) {
secureStore.savePassword(StringUtils.joinWith("|", "account", auth.getClient()), auth.getKey());
}
break;
case DEVICE_CODE:
authMethodDetailsResult = call(this::doDeviceLogin, "dc");
break;
case AZURE_CLI:
authMethodDetailsResult = call(() -> checkCanceled(indicator, IdentityAzureManager.getInstance().signInAzureCli()), "az");
break;
case OAUTH2:
authMethodDetailsResult = call(() -> checkCanceled(indicator, IdentityAzureManager.getInstance().signInOAuth()), "oauth");
break;
default:
break;
}
return authMethodDetailsResult;
}
Expand Down Expand Up @@ -264,27 +279,10 @@ private void disableAzureCliLogin() {
azureCliRadioButton.setText("Azure CLI (Not logged in)");
}

private AuthMethodDetails doServicePrincipalLoginInternal(AuthConfiguration auth) {
try {
IdentityAzureManager authManager = IdentityAzureManager.getInstance();
if (AuthMethodManager.getInstance().isSignedIn()) {
doSignOut();
}
return authManager.signInServicePrincipal(auth).block();
} catch (Exception ex) {
ex.printStackTrace();
ErrorWindow.show(project, ex.getMessage(), SIGN_IN_ERROR);
}
return new AuthMethodDetails();
}

@Nullable
private synchronized AuthMethodDetails doDeviceLogin() {
CompletableFuture<AuthMethodDetails> deviceCodeLoginFuture = new CompletableFuture<>();
try {
if (AuthMethodManager.getInstance().isSignedIn()) {
doSignOut();
}
final IDeviceLoginUI deviceLoginUI = CommonSettings.getUiFactory().getDeviceLoginUI();
final AzureAccount az = com.microsoft.azure.toolkit.lib.Azure.az(AzureAccount.class);
final Account account = az.loginAsync(AuthType.DEVICE_CODE, true).block();
Expand Down