77
88import com .intellij .openapi .application .ApplicationManager ;
99import com .intellij .openapi .diagnostic .Logger ;
10- import com .intellij .openapi .fileChooser .FileChooser ;
11- import com .intellij .openapi .fileChooser .FileChooserDescriptor ;
12- import com .intellij .openapi .fileChooser .FileChooserDescriptorFactory ;
1310import com .intellij .openapi .progress .ProcessCanceledException ;
1411import com .intellij .openapi .progress .ProgressIndicator ;
1512import com .intellij .openapi .progress .ProgressManager ;
1613import com .intellij .openapi .project .Project ;
1714import com .intellij .openapi .ui .DialogWrapper ;
18- import com .intellij .openapi .ui .Messages ;
19- import com .intellij .openapi .vfs .LocalFileSystem ;
20- import com .intellij .openapi .vfs .VirtualFile ;
2115import com .intellij .ui .AnimatedIcon ;
2216import com .microsoft .azure .toolkit .lib .Azure ;
2317import com .microsoft .azure .toolkit .lib .auth .Account ;
2418import com .microsoft .azure .toolkit .lib .auth .AzureAccount ;
2519import com .microsoft .azure .toolkit .lib .auth .core .devicecode .DeviceCodeAccount ;
2620import com .microsoft .azure .toolkit .lib .auth .model .AccountEntity ;
21+ import com .microsoft .azure .toolkit .lib .auth .model .AuthConfiguration ;
2722import com .microsoft .azure .toolkit .lib .auth .model .AuthType ;
2823import com .microsoft .azure .toolkit .lib .auth .util .AzureEnvironmentUtils ;
2924import com .microsoft .azure .toolkit .lib .common .exception .AzureToolkitRuntimeException ;
3227import com .microsoft .azure .toolkit .lib .common .task .AzureTask ;
3328import com .microsoft .azure .toolkit .lib .common .task .AzureTaskManager ;
3429import com .microsoft .azuretools .adauth .IDeviceLoginUI ;
35- import com .microsoft .azuretools .adauth .StringUtils ;
3630import com .microsoft .azuretools .authmanage .*;
3731import com .microsoft .azuretools .authmanage .models .AuthMethodDetails ;
38- import com .microsoft .azuretools .authmanage .models .SubscriptionDetail ;
3932import com .microsoft .azuretools .sdkmanage .IdentityAzureManager ;
4033import com .microsoft .azuretools .telemetrywrapper .*;
34+ import com .microsoft .intellij .secure .IdeaSecureStore ;
4135import com .microsoft .intellij .ui .components .AzureDialogWrapper ;
42- import com .microsoft .intellij .util .PluginUtil ;
43- import com .microsoft .tooling .msservices .components .DefaultLoader ;
4436import org .apache .commons .collections4 .CollectionUtils ;
37+ import org .apache .commons .lang3 .StringUtils ;
4538import org .jdesktop .swingx .JXHyperlink ;
4639import org .jetbrains .annotations .Nullable ;
4740import reactor .core .Disposable ;
5548import java .awt .*;
5649import java .net .URI ;
5750import java .time .Duration ;
58- import java .util .List ;
5951import java .util .*;
6052import java .util .concurrent .Callable ;
6153import java .util .concurrent .CancellationException ;
@@ -73,10 +65,6 @@ public class SignInWindow extends AzureDialogWrapper {
7365 private JRadioButton deviceLoginRadioButton ;
7466
7567 private JRadioButton spRadioButton ;
76- private JLabel authFileLabel ;
77- private JTextField authFileTextField ;
78- private JButton browseButton ;
79- private JButton createNewAuthenticationFileButton ;
8068 private JLabel servicePrincipalCommentLabel ;
8169 private JLabel deviceLoginCommentLabel ;
8270 private JRadioButton azureCliRadioButton ;
@@ -90,7 +78,7 @@ public class SignInWindow extends AzureDialogWrapper {
9078 private String accountEmail ;
9179
9280 private Project project ;
93- private Map <AbstractButton , List < JComponent > > radioButtonComponentsMap = new HashMap <>(3 );
81+ private Map <AbstractButton , JComponent > radioButtonComponentsMap = new HashMap <>(3 );
9482
9583 public SignInWindow (AuthMethodDetails authMethodDetails , Project project ) {
9684 super (project , true , IdeModalityType .PROJECT );
@@ -100,7 +88,6 @@ public SignInWindow(AuthMethodDetails authMethodDetails, Project project) {
10088 setOKButtonText ("Sign in" );
10189
10290 this .authMethodDetails = authMethodDetails ;
103- authFileTextField .setText (authMethodDetails == null ? null : authMethodDetails .getCredFilePath ());
10491
10592 oauthLoginRadioButton .addItemListener (e -> refreshAuthControlElements ());
10693
@@ -110,15 +97,6 @@ public SignInWindow(AuthMethodDetails authMethodDetails, Project project) {
11097
11198 azureCliRadioButton .addActionListener (e -> refreshAuthControlElements ());
11299
113- browseButton .addActionListener (e -> {
114- refreshAuthControlElements ();
115- doSelectCredFilepath ();
116- });
117-
118- createNewAuthenticationFileButton .addActionListener (e -> {
119- refreshAuthControlElements ();
120- doCreateServicePrincipal ();
121- });
122100
123101 ButtonGroup buttonGroup = new ButtonGroup ();
124102 buttonGroup .add (oauthLoginRadioButton );
@@ -127,14 +105,12 @@ public SignInWindow(AuthMethodDetails authMethodDetails, Project project) {
127105 buttonGroup .add (azureCliRadioButton );
128106 azureCliRadioButton .setSelected (true );
129107
130- radioButtonComponentsMap .put (spRadioButton , Arrays .asList (servicePrincipalCommentLabel ,
131- authFileLabel , authFileTextField , browseButton , createNewAuthenticationFileButton ));
132- radioButtonComponentsMap .put (deviceLoginRadioButton , Collections .singletonList (deviceLoginCommentLabel ));
133-
134- radioButtonComponentsMap .put (oauthLoginRadioButton , Collections .singletonList (labelOAuthLogin ));
135-
136- radioButtonComponentsMap .put (azureCliRadioButton , Collections .singletonList (azureCliCommentLabel ));
108+ radioButtonComponentsMap .put (spRadioButton , servicePrincipalCommentLabel );
109+ radioButtonComponentsMap .put (deviceLoginRadioButton , deviceLoginCommentLabel );
110+ radioButtonComponentsMap .put (oauthLoginRadioButton , labelOAuthLogin );
111+ radioButtonComponentsMap .put (azureCliRadioButton , azureCliCommentLabel );
137112 init ();
113+ this .setOKActionEnabled (false );
138114 checkAccountAvailability ();
139115 }
140116
@@ -188,22 +164,21 @@ public Single<AuthMethodDetails> login() {
188164 return AzureTaskManager .getInstance ().runInModalAsObservable (task ).toSingle ();
189165 }
190166
167+ private static final IdeaSecureStore secureStore = IdeaSecureStore .getInstance ();
168+
191169 private @ Nullable AuthMethodDetails doLogin (ProgressIndicator indicator ) {
192170 authMethodDetailsResult = new AuthMethodDetails ();
193171 if (spRadioButton .isSelected ()) { // automated
194172 final Map <String , String > properties = new HashMap <>();
195173 properties .put (AZURE_ENVIRONMENT , CommonSettings .getEnvironment ().getName ());
196174 properties .putAll (signInSPProp );
197175 EventUtil .logEvent (EventType .info , ACCOUNT , SIGNIN , properties , null );
198- final String authPath = authFileTextField .getText ();
199- if (StringUtils .isNullOrWhiteSpace (authPath )) {
200- final String title = "Sign in dialog info" ;
201- final String message = "Select authentication file" ;
202- DefaultLoader .getUIHelper ().showMessageDialog (contentPane , message , title , Messages .getInformationIcon ());
203- return null ;
204- }
205176
206- authMethodDetailsResult = doServicePrincipalLogin (authPath );
177+ if (ApplicationManager .getApplication ().isDispatchThread ()) {
178+ doServicePrincipalLogin ();
179+ } else {
180+ AzureTaskManager .getInstance ().runAndWait (() -> doServicePrincipalLogin ());
181+ }
207182 } else if (deviceLoginRadioButton .isSelected ()) {
208183 authMethodDetailsResult = doDeviceLogin ();
209184 } else if (azureCliRadioButton .isSelected ()) {
@@ -214,6 +189,18 @@ public Single<AuthMethodDetails> login() {
214189 return authMethodDetailsResult ;
215190 }
216191
192+ private void doServicePrincipalLogin () {
193+ final ServicePrincipalLoginDialog dialog = new ServicePrincipalLoginDialog (project );
194+ if (dialog .showAndGet ()) {
195+ AuthConfiguration data = dialog .getData ();
196+ authMethodDetailsResult = doServicePrincipalLoginInternal (data );
197+ if (StringUtils .isNotBlank (data .getKey ())) {
198+ secureStore .savePassword ("account" , data .getClient (), data .getKey ());
199+ }
200+
201+ }
202+ }
203+
217204 private static AuthMethodDetails checkCanceled (ProgressIndicator indicator , Mono <? extends AuthMethodDetails > mono ) {
218205 CompletableFuture <? extends AuthMethodDetails > future = mono .toFuture ();
219206 Disposable disposable = Flux .interval (Duration .ofSeconds (1 )).map (ts -> {
@@ -249,7 +236,8 @@ protected void init() {
249236 }
250237
251238 private void refreshAuthControlElements () {
252- radioButtonComponentsMap .keySet ().forEach (radio -> radioButtonComponentsMap .get (radio ).forEach (comp -> comp .setEnabled (radio .isSelected ())));
239+ radioButtonComponentsMap .keySet ().forEach (radio -> radioButtonComponentsMap .get (radio ).setEnabled (radio .isSelected ()));
240+ this .setOKActionEnabled (true );
253241 }
254242
255243 private void checkAccountAvailability () {
@@ -268,7 +256,7 @@ private void checkAccountAvailability() {
268256 oauthLoginRadioButton .setEnabled (false );
269257 labelOAuthLogin .setEnabled (false );
270258 }
271-
259+ this . setOKActionEnabled ( true );
272260 if (accounts .stream ().anyMatch (ac -> ac .getAuthType () == AuthType .DEVICE_CODE )) {
273261 deviceLoginRadioButton .setEnabled (true );
274262 deviceLoginCommentLabel .setEnabled (true );
@@ -301,27 +289,13 @@ private void disableAzureCliLogin() {
301289 azureCliRadioButton .setText ("Azure CLI (Not logged in)" );
302290 }
303291
304- private void doSelectCredFilepath () {
305- FileChooserDescriptor fileDescriptor = FileChooserDescriptorFactory .createSingleFileDescriptor ("azureauth" );
306- fileDescriptor .setTitle ("Select Authentication File" );
307- final VirtualFile file = FileChooser .chooseFile (
308- fileDescriptor ,
309- this .project ,
310- LocalFileSystem .getInstance ().findFileByPath (System .getProperty ("user.home" ))
311- );
312- if (file != null ) {
313- authFileTextField .setText (file .getPath ());
314- }
315- }
316-
317- private AuthMethodDetails doServicePrincipalLogin (final String authPath ) {
292+ private AuthMethodDetails doServicePrincipalLoginInternal (AuthConfiguration auth ) {
318293 try {
319294 IdentityAzureManager authManager = IdentityAzureManager .getInstance ();
320295 if (AuthMethodManager .getInstance ().isSignedIn ()) {
321296 doSignOut ();
322297 }
323- return authManager .signInServicePrincipal (AuthFile .fromFile (authPath )).block ();
324-
298+ return authManager .signInServicePrincipal (auth ).block ();
325299 } catch (Exception ex ) {
326300 ex .printStackTrace ();
327301 ErrorWindow .show (project , ex .getMessage (), SIGN_IN_ERROR );
@@ -400,82 +374,4 @@ private void doSignOut() {
400374 ErrorWindow .show (project , ex .getMessage (), "Sign Out Error" );
401375 }
402376 }
403-
404- private void doCreateServicePrincipal () {
405- final AuthMethodManager authMethodManager = AuthMethodManager .getInstance ();
406- final IdentityAzureManager dcAuthManager = IdentityAzureManager .getInstance ();
407- try {
408- if (authMethodManager .isSignedIn ()) {
409- authMethodManager .signOut ();
410- }
411- doDeviceLogin ();
412- if (!dcAuthManager .isSignedIn ()) {
413- System .out .println (">> Canceled by the user" );
414- return ;
415- }
416-
417- final SubscriptionManager subscriptionManager = dcAuthManager .getSubscriptionManager ();
418-
419- Optional .ofNullable (ProgressManager .getInstance ().getProgressIndicator ()).ifPresent (indicator -> indicator .setText2 ("Loading subscriptions..." ));
420- subscriptionManager .getSubscriptionDetails ();
421-
422- final SrvPriSettingsDialog d = SrvPriSettingsDialog .go (subscriptionManager .getSubscriptionDetails (), project );
423- final List <SubscriptionDetail > subscriptionDetailsUpdated ;
424- final String destinationFolder ;
425- if (d != null ) {
426- subscriptionDetailsUpdated = d .getSubscriptionDetails ();
427- destinationFolder = d .getDestinationFolder ();
428- } else {
429- System .out .println (">> Canceled by the user" );
430- return ;
431- }
432-
433- Map <String , List <String >> tidSidsMap = new HashMap <>();
434- for (SubscriptionDetail sd : subscriptionDetailsUpdated ) {
435- if (sd .isSelected ()) {
436- System .out .format (">> %s\n " , sd .getSubscriptionName ());
437- String tid = sd .getTenantId ();
438- List <String > sidList ;
439- if (!tidSidsMap .containsKey (tid )) {
440- sidList = new LinkedList <>();
441- } else {
442- sidList = tidSidsMap .get (tid );
443- }
444- sidList .add (sd .getSubscriptionId ());
445- tidSidsMap .put (tid , sidList );
446- }
447- }
448-
449- SrvPriCreationStatusDialog d1 = SrvPriCreationStatusDialog
450- .go (dcAuthManager , tidSidsMap , destinationFolder , project );
451- if (d1 == null ) {
452- System .out .println (">> Canceled by the user" );
453- return ;
454- }
455-
456- String path = d1 .getSelectedAuthFilePath ();
457- if (path == null ) {
458- System .out .println (">> No file was created" );
459- return ;
460- }
461-
462- authFileTextField .setText (path );
463- PluginUtil .displayInfoDialog ("Authentication File Created" , String .format (
464- "Your credentials have been exported to %s, please keep the authentication file safe" , path ));
465- } catch (Exception ex ) {
466- ex .printStackTrace ();
467- //LOGGER.error("doCreateServicePrincipal", ex);
468- ErrorWindow .show (project , ex .getMessage (), "Get Subscription Error" );
469-
470- } finally {
471- if (dcAuthManager != null ) {
472- try {
473- System .out .println (">> Signing out..." );
474- AuthMethodManager .getInstance ().signOut ();
475- } catch (Exception e ) {
476- e .printStackTrace ();
477- }
478- }
479- }
480- }
481377}
0 commit comments