Skip to content

Commit 4b8ee98

Browse files
authored
Provide more appropriate error message for invalid API key (#6771)
1 parent 3b749fd commit 4b8ee98

4 files changed

Lines changed: 40 additions & 25 deletions

File tree

api/src/org/labkey/api/security/AuthenticationManager.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,6 @@
119119
import java.util.stream.Collectors;
120120

121121
import static org.labkey.api.action.SpringActionController.ERROR_MSG;
122-
import static org.labkey.api.security.AuthenticationProvider.FailureReason.complexity;
123-
import static org.labkey.api.security.AuthenticationProvider.FailureReason.expired;
124122

125123
public class AuthenticationManager
126124
{
@@ -668,6 +666,14 @@ public void addUserErrorMessage(BindException errors, PrimaryAuthenticationResul
668666
throw new IllegalStateException("Shouldn't be adding an error message in success case");
669667
}
670668
},
669+
BadApiKey
670+
{
671+
@Override
672+
public void addUserErrorMessage(BindException errors, PrimaryAuthenticationResult result, @Nullable String fullEmailAddress, @Nullable URLHelper returnUrl, DisplayLocation location)
673+
{
674+
errors.reject(ERROR_MSG, "The API key you provided is invalid.");
675+
}
676+
},
671677
BadCredentials
672678
{
673679
@Override
@@ -1031,24 +1037,22 @@ else if (null != emailAddress)
10311037
{
10321038
// Funny audit case -- user doesn't exist, so there's no user to associate with the event. Use guest.
10331039
addAuditEvent(User.guest, request, "Unknown user" + message);
1034-
_log.warn("Unknown user" + message);
1040+
_log.warn("Unknown user{}", message);
10351041
}
10361042

10371043
// For now, redirectURL is only checked in the failure case, see #19778 for some history on redirect handling
10381044
ActionURL redirectURL = firstFailure.getRedirectURL();
10391045

1040-
// if labkey db authentication determines password has expired or does not meet requirements then return
1041-
// result with appropriate status. Note that redirectUrl might be null (e.g., API case).
1046+
// If labkey db authentication determines password has expired or does not meet requirements then return
1047+
// result with appropriate status. Same with a bad API key. Note that redirectUrl might be null (e.g., API case).
10421048
FailureReason firstFailureReason = firstFailure.getFailureReason();
1043-
if (firstFailureReason == expired)
1044-
{
1045-
return new PrimaryAuthenticationResult(redirectURL, AuthenticationStatus.PasswordExpired);
1046-
}
1047-
else if (firstFailureReason == complexity)
1049+
AuthenticationStatus status = firstFailureReason.getAssociatedStatus();
1050+
if (null != status)
10481051
{
1049-
return new PrimaryAuthenticationResult(redirectURL, AuthenticationStatus.Complexity);
1052+
return new PrimaryAuthenticationResult(redirectURL, status);
10501053
}
1051-
else if (null != redirectURL)
1054+
1055+
if (null != redirectURL)
10521056
{
10531057
throw new RedirectException(redirectURL);
10541058
}
@@ -1145,7 +1149,7 @@ private static PrimaryAuthenticationResult _beforeAuthenticate(HttpServletReques
11451149
long delay = 0;
11461150

11471151
// slow down login attempts when we detect more than 20/minute bad attempts per user, password, or ip address
1148-
rl = addrLimiter.get(_toKey(request==null?null:request.getRemoteAddr()));
1152+
rl = addrLimiter.get(_toKey(request == null ? null : request.getRemoteAddr()));
11491153
if (null != rl)
11501154
delay = Math.max(delay,rl.add(0, false));
11511155
rl = pwdLimiter.get(_toKey(pwd));

api/src/org/labkey/api/security/AuthenticationProvider.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.labkey.api.security.AuthenticationConfiguration.PrimaryAuthenticationConfiguration;
2828
import org.labkey.api.security.AuthenticationConfiguration.SSOAuthenticationConfiguration;
2929
import org.labkey.api.security.AuthenticationConfiguration.SecondaryAuthenticationConfiguration;
30+
import org.labkey.api.security.AuthenticationManager.AuthenticationStatus;
3031
import org.labkey.api.security.AuthenticationManager.AuthenticationValidator;
3132
import org.labkey.api.security.ValidEmail.InvalidEmailException;
3233
import org.labkey.api.settings.StandardStartupPropertyHandler;
@@ -452,14 +453,14 @@ public AuthenticationResponse setRequireSecondary(boolean requireSecondary)
452453
// hackers). We try to be as specific as possible.
453454
enum FailureReason
454455
{
455-
userDoesNotExist(ReportType.onFailure, "user does not exist"),
456-
badPassword(ReportType.onFailure, "incorrect password"),
457-
badCredentials(ReportType.onFailure, "invalid credentials"), // Use for cases where we can't distinguish between userDoesNotExist and badPassword
458-
complexity(ReportType.onFailure, "password does not meet the complexity requirements"),
459-
expired(ReportType.onFailure, "password has expired"),
460-
configurationError(ReportType.always, "configuration problem"),
461-
notApplicable(ReportType.never, "not applicable"),
462-
badApiKey(ReportType.onFailure, "invalid API key") {
456+
userDoesNotExist(ReportType.onFailure, "user does not exist", null),
457+
badPassword(ReportType.onFailure, "incorrect password", null),
458+
badCredentials(ReportType.onFailure, "invalid credentials", null), // Use for cases where we can't distinguish between userDoesNotExist and badPassword
459+
complexity(ReportType.onFailure, "password does not meet the complexity requirements", AuthenticationStatus.Complexity),
460+
expired(ReportType.onFailure, "password has expired", AuthenticationStatus.PasswordExpired),
461+
configurationError(ReportType.always, "configuration problem", null),
462+
notApplicable(ReportType.never, "not applicable", null),
463+
badApiKey(ReportType.onFailure, "invalid API key", AuthenticationStatus.BadApiKey) {
463464
@Override
464465
public @Nullable String getEmailAddress(ValidEmail email) throws InvalidEmailException
465466
{
@@ -471,11 +472,13 @@ enum FailureReason
471472

472473
private final ReportType _type;
473474
private final String _message;
475+
private final @Nullable AuthenticationStatus _associatedStatus;
474476

475-
FailureReason(ReportType type, String message)
477+
FailureReason(ReportType type, String message, @Nullable AuthenticationStatus associatedStatus)
476478
{
477479
_type = type;
478480
_message = message;
481+
_associatedStatus = associatedStatus;
479482
}
480483

481484
public ReportType getReportType()
@@ -492,6 +495,11 @@ public String getMessage()
492495
{
493496
return email.getEmailAddress();
494497
}
498+
499+
public @Nullable AuthenticationStatus getAssociatedStatus()
500+
{
501+
return _associatedStatus;
502+
}
495503
}
496504

497505
enum ReportType

core/src/org/labkey/core/login/LoginController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ private static boolean authenticate(LoginForm form, BindException errors, HttpSe
317317
try
318318
{
319319
// Attempt authentication with all active form providers
320-
PrimaryAuthenticationResult result = AuthenticationManager.authenticate(request, form.getEmail(), form.getPassword(), form.getReturnUrlHelper(), true);
320+
String formEmail = form.getEmail();
321+
PrimaryAuthenticationResult result = AuthenticationManager.authenticate(request, formEmail, form.getPassword(), form.getReturnUrlHelper(), true);
321322
AuthenticationStatus status = result.getStatus();
322323

323324
if (Success == status)
@@ -328,7 +329,7 @@ private static boolean authenticate(LoginForm form, BindException errors, HttpSe
328329
else
329330
{
330331
// Explicit test for valid email
331-
ValidEmail email = new ValidEmail(form.getEmail());
332+
ValidEmail email = SecurityManager.API_KEY.equals(formEmail) ? null : new ValidEmail(formEmail);
332333

333334
if (status.handleRedirect())
334335
{
@@ -337,7 +338,7 @@ private static boolean authenticate(LoginForm form, BindException errors, HttpSe
337338
else
338339
{
339340
// Pass in normalized email address, but only if user provided a full email address
340-
status.addUserErrorMessage(errors, result, form.getEmail().contains("@") ? email.getEmailAddress() : null, form.getReturnUrlHelper());
341+
status.addUserErrorMessage(errors, result, formEmail.contains("@") ? email.getEmailAddress() : null, form.getReturnUrlHelper());
341342
}
342343
}
343344
}

core/src/org/labkey/core/user/UserController.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,7 @@ public boolean isActivate()
628628
return activate;
629629
}
630630

631+
@SuppressWarnings("unused")
631632
public void setActivate(boolean activate)
632633
{
633634
this.activate = activate;
@@ -638,6 +639,7 @@ public boolean isDelete()
638639
return delete;
639640
}
640641

642+
@SuppressWarnings("unused")
641643
public void setDelete(boolean delete)
642644
{
643645
this.delete = delete;

0 commit comments

Comments
 (0)