Skip to content

Commit eec4f13

Browse files
authored
Merge pull request #43 from Infisical/fix/organization-id-on-non-browser-login
fix: added organization id flag and prompt for non-browser login
2 parents 8aae7ea + 174b151 commit eec4f13

File tree

2 files changed

+103
-83
lines changed

2 files changed

+103
-83
lines changed

packages/cmd/login.go

Lines changed: 100 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,25 @@ var loginCmd = &cobra.Command{
199199
fmt.Printf("Login via browser failed. %s\n", err.Error())
200200
useBrowserLogin = false
201201
}
202-
} else {
202+
}
203+
204+
// if not using browser login or if the browser login failed, get login credentials from command line or environment variables
205+
if !useBrowserLogin {
203206
email, password, err := getLoginCredentials(cmd, isDirectUserLoginFlagsAndEnvsSet)
204207
if err != nil {
205208
util.HandleError(err)
206209
}
207210

208-
cliDefaultLogin(&userCredentialsToBeStored, email, password)
211+
var organizationId string
212+
213+
if isDirectUserLoginFlagsAndEnvsSet {
214+
organizationId, err = util.GetCmdFlagOrEnv(cmd, "organization-id", []string{"INFISICAL_ORGANIZATION_ID"})
215+
if err != nil {
216+
util.HandleError(err)
217+
}
218+
}
219+
220+
cliDefaultLogin(&userCredentialsToBeStored, email, password, organizationId)
209221
}
210222

211223
err = util.StoreUserCredsInKeyRing(&userCredentialsToBeStored)
@@ -285,82 +297,83 @@ var loginCmd = &cobra.Command{
285297
},
286298
}
287299

288-
func cliDefaultLogin(userCredentialsToBeStored *models.UserCredentials, email string, password string) {
300+
func cliDefaultLogin(userCredentialsToBeStored *models.UserCredentials, email string, password string, organizationId string) {
289301
loginV3Response, err := getFreshUserCredentials(email, password)
290-
if err == nil {
291-
userCredentialsToBeStored.Email = email
292-
userCredentialsToBeStored.PrivateKey = ""
293-
userCredentialsToBeStored.JTWToken = loginV3Response.AccessToken
294-
return
295-
}
302+
var getOrganizationIdAccessToken string
296303

297-
// TODO(daniel): At a later time we should re-add this check, but we don't want to break older Infisical instances that doesn't have the latest SRP removal initiative on them.
298-
// if !strings.Contains(err.Error(), "LegacyEncryptionScheme") {
299-
// util.HandleError(err)
300-
// }
304+
if err == nil {
305+
getOrganizationIdAccessToken = loginV3Response.AccessToken
306+
} else {
307+
log.Info().Msg("Unable to authenticate with the provided credentials, falling back to SRP authentication")
301308

302-
log.Info().Msg("Unable to authenticate with the provided credentials, falling back to SRP authentication")
309+
_, loginTwoResponse, err := getFreshUserCredentialsWithSrp(email, password)
310+
if err != nil {
311+
fmt.Println("Unable to authenticate with the provided credentials, please try again")
312+
log.Debug().Err(err)
313+
//return here
314+
util.HandleError(err)
315+
}
303316

304-
_, loginTwoResponse, err := getFreshUserCredentialsWithSrp(email, password)
305-
if err != nil {
306-
fmt.Println("Unable to authenticate with the provided credentials, please try again")
307-
log.Debug().Err(err)
308-
//return here
309-
util.HandleError(err)
310-
}
317+
if loginTwoResponse.MfaEnabled {
318+
i := 1
319+
for i < 6 {
320+
mfaVerifyCode := askForMFACode("email")
311321

312-
if loginTwoResponse.MfaEnabled {
313-
i := 1
314-
for i < 6 {
315-
mfaVerifyCode := askForMFACode("email")
322+
httpClient, err := util.GetRestyClientWithCustomHeaders()
323+
if err != nil {
324+
util.HandleError(err, "Unable to get resty client with custom headers")
325+
}
326+
httpClient.SetAuthToken(loginTwoResponse.Token)
327+
verifyMFAresponse, mfaErrorResponse, requestError := api.CallVerifyMfaToken(httpClient, api.VerifyMfaTokenRequest{
328+
Email: email,
329+
MFAToken: mfaVerifyCode,
330+
})
316331

317-
httpClient, err := util.GetRestyClientWithCustomHeaders()
318-
if err != nil {
319-
util.HandleError(err, "Unable to get resty client with custom headers")
320-
}
321-
httpClient.SetAuthToken(loginTwoResponse.Token)
322-
verifyMFAresponse, mfaErrorResponse, requestError := api.CallVerifyMfaToken(httpClient, api.VerifyMfaTokenRequest{
323-
Email: email,
324-
MFAToken: mfaVerifyCode,
325-
})
332+
if requestError != nil {
333+
util.HandleError(err)
334+
break
335+
} else if mfaErrorResponse != nil {
336+
if mfaErrorResponse.Context.Code == "mfa_invalid" {
337+
msg := fmt.Sprintf("Incorrect, verification code. You have %v attempts left", 5-i)
338+
fmt.Println(msg)
339+
if i == 5 {
340+
util.PrintErrorMessageAndExit("No tries left, please try again in a bit")
341+
break
342+
}
343+
}
326344

327-
if requestError != nil {
328-
util.HandleError(err)
329-
break
330-
} else if mfaErrorResponse != nil {
331-
if mfaErrorResponse.Context.Code == "mfa_invalid" {
332-
msg := fmt.Sprintf("Incorrect, verification code. You have %v attempts left", 5-i)
333-
fmt.Println(msg)
334-
if i == 5 {
335-
util.PrintErrorMessageAndExit("No tries left, please try again in a bit")
345+
if mfaErrorResponse.Context.Code == "mfa_expired" {
346+
util.PrintErrorMessageAndExit("Your 2FA verification code has expired, please try logging in again")
336347
break
337348
}
338-
}
349+
i++
350+
} else {
351+
loginTwoResponse.EncryptedPrivateKey = verifyMFAresponse.EncryptedPrivateKey
352+
loginTwoResponse.EncryptionVersion = verifyMFAresponse.EncryptionVersion
353+
loginTwoResponse.Iv = verifyMFAresponse.Iv
354+
loginTwoResponse.ProtectedKey = verifyMFAresponse.ProtectedKey
355+
loginTwoResponse.ProtectedKeyIV = verifyMFAresponse.ProtectedKeyIV
356+
loginTwoResponse.ProtectedKeyTag = verifyMFAresponse.ProtectedKeyTag
357+
loginTwoResponse.PublicKey = verifyMFAresponse.PublicKey
358+
loginTwoResponse.Tag = verifyMFAresponse.Tag
359+
loginTwoResponse.Token = verifyMFAresponse.Token
360+
loginTwoResponse.EncryptionVersion = verifyMFAresponse.EncryptionVersion
339361

340-
if mfaErrorResponse.Context.Code == "mfa_expired" {
341-
util.PrintErrorMessageAndExit("Your 2FA verification code has expired, please try logging in again")
342362
break
343363
}
344-
i++
345-
} else {
346-
loginTwoResponse.EncryptedPrivateKey = verifyMFAresponse.EncryptedPrivateKey
347-
loginTwoResponse.EncryptionVersion = verifyMFAresponse.EncryptionVersion
348-
loginTwoResponse.Iv = verifyMFAresponse.Iv
349-
loginTwoResponse.ProtectedKey = verifyMFAresponse.ProtectedKey
350-
loginTwoResponse.ProtectedKeyIV = verifyMFAresponse.ProtectedKeyIV
351-
loginTwoResponse.ProtectedKeyTag = verifyMFAresponse.ProtectedKeyTag
352-
loginTwoResponse.PublicKey = verifyMFAresponse.PublicKey
353-
loginTwoResponse.Tag = verifyMFAresponse.Tag
354-
loginTwoResponse.Token = verifyMFAresponse.Token
355-
loginTwoResponse.EncryptionVersion = verifyMFAresponse.EncryptionVersion
356-
357-
break
358364
}
359365
}
366+
367+
getOrganizationIdAccessToken = loginTwoResponse.Token
360368
}
361369

370+
// TODO(daniel): At a later time we should re-add this check, but we don't want to break older Infisical instances that doesn't have the latest SRP removal initiative on them.
371+
// if !strings.Contains(err.Error(), "LegacyEncryptionScheme") {
372+
// util.HandleError(err)
373+
// }
374+
362375
// Login is successful so ask user to choose organization
363-
newJwtToken := GetJwtTokenWithOrganizationId(loginTwoResponse.Token, email)
376+
newJwtToken := GetJwtTokenWithOrganizationId(getOrganizationIdAccessToken, email, organizationId)
364377

365378
//updating usercredentials
366379
userCredentialsToBeStored.Email = email
@@ -388,6 +401,7 @@ func init() {
388401
loginCmd.Flags().String("oidc-jwt", "", "JWT for OIDC authentication. Deprecated, use --jwt instead")
389402
loginCmd.Flags().String("email", "", "email for 'user' login method")
390403
loginCmd.Flags().String("password", "", "password for 'user' login method")
404+
loginCmd.Flags().String("organization-id", "", "organization id for 'user' login method")
391405

392406
loginCmd.Flags().MarkDeprecated("oidc-jwt", "use --jwt instead")
393407

@@ -659,7 +673,7 @@ func getFreshUserCredentialsWithSrp(email string, password string) (*api.GetLogi
659673
return &loginOneResponseResult, &loginTwoResponseResult, nil
660674
}
661675

662-
func GetJwtTokenWithOrganizationId(oldJwtToken string, email string) string {
676+
func GetJwtTokenWithOrganizationId(oldJwtToken string, email string, organizationId string) string {
663677
log.Debug().Msg(fmt.Sprint("GetJwtTokenWithOrganizationId: ", "oldJwtToken", oldJwtToken))
664678

665679
httpClient, err := util.GetRestyClientWithCustomHeaders()
@@ -668,29 +682,33 @@ func GetJwtTokenWithOrganizationId(oldJwtToken string, email string) string {
668682
}
669683
httpClient.SetAuthToken(oldJwtToken)
670684

671-
organizationResponse, err := api.CallGetAllOrganizations(httpClient)
685+
selectedOrganizationId := organizationId
672686

673-
if err != nil {
674-
util.HandleError(err, "Unable to pull organizations that belong to you")
675-
}
687+
if selectedOrganizationId == "" {
688+
organizationResponse, err := api.CallGetAllOrganizations(httpClient)
676689

677-
organizations := organizationResponse.Organizations
690+
if err != nil {
691+
util.HandleError(err, "Unable to pull organizations that belong to you")
692+
}
678693

679-
organizationNames := util.GetOrganizationsNameList(organizationResponse)
694+
organizations := organizationResponse.Organizations
680695

681-
prompt := promptui.Select{
682-
Label: "Which Infisical organization would you like to log into?",
683-
Items: organizationNames,
684-
}
696+
organizationNames := util.GetOrganizationsNameList(organizationResponse)
685697

686-
index, _, err := prompt.Run()
687-
if err != nil {
688-
util.HandleError(err)
689-
}
698+
prompt := promptui.Select{
699+
Label: "Which Infisical organization would you like to log into?",
700+
Items: organizationNames,
701+
}
690702

691-
selectedOrganization := organizations[index]
703+
index, _, err := prompt.Run()
704+
if err != nil {
705+
util.HandleError(err)
706+
}
707+
708+
selectedOrganizationId = organizations[index].ID
709+
}
692710

693-
selectedOrgRes, err := api.CallSelectOrganization(httpClient, api.SelectOrganizationRequest{OrganizationId: selectedOrganization.ID})
711+
selectedOrgRes, err := api.CallSelectOrganization(httpClient, api.SelectOrganizationRequest{OrganizationId: selectedOrganizationId})
694712
if err != nil {
695713
util.HandleError(err)
696714
}
@@ -730,7 +748,7 @@ func GetJwtTokenWithOrganizationId(oldJwtToken string, email string) string {
730748
i++
731749
} else {
732750
httpClient.SetAuthToken(verifyMFAresponse.Token)
733-
selectedOrgRes, err = api.CallSelectOrganization(httpClient, api.SelectOrganizationRequest{OrganizationId: selectedOrganization.ID})
751+
selectedOrgRes, err = api.CallSelectOrganization(httpClient, api.SelectOrganizationRequest{OrganizationId: selectedOrganizationId})
734752
break
735753
}
736754
}
@@ -961,8 +979,9 @@ func browserLoginHandler(success chan models.UserCredentials, failure chan error
961979
// check if one of the flag or all the envs are set
962980
func validateDirectUserLoginFlagsAndEnvsSet(cmd *cobra.Command, domain string) (isDirectUserLogin bool, err error) {
963981
requiredFlagsEnvs := map[string]string{
964-
"email": "INFISICAL_EMAIL",
965-
"password": "INFISICAL_PASSWORD",
982+
"email": "INFISICAL_EMAIL",
983+
"password": "INFISICAL_PASSWORD",
984+
"organization-id": "INFISICAL_ORGANIZATION_ID",
966985
}
967986

968987
var missingFlagsEnvs []string

packages/util/constants.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ const (
3535
// JWT AUTH
3636
INFISICAL_JWT_NAME = "INFISICAL_JWT"
3737
// LDAP AUTH
38-
INFISICAL_LDAP_USERNAME = "INFISICAL_LDAP_USERNAME"
39-
INFISICAL_LDAP_PASSWORD = "INFISICAL_LDAP_PASSWORD"
38+
INFISICAL_LDAP_USERNAME = "INFISICAL_LDAP_USERNAME"
39+
INFISICAL_LDAP_PASSWORD = "INFISICAL_LDAP_PASSWORD"
40+
INFISICAL_ORGANIZATION_ID = "INFISICAL_ORGANIZATION_ID"
4041

4142
INFISICAL_GATEWAY_TOKEN_NAME_LEGACY = "TOKEN" // backwards compatibility with gateway helm chart, where token was the only supported auth method
4243

0 commit comments

Comments
 (0)