-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature/Identity] Fixes test failures in gradle check for #4798 #5441
Changes from all commits
2654f95
6af5fdf
bed4aaf
0be5ce3
3153ba7
dea9f34
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,7 +66,27 @@ public void login(AuthenticationToken authenticationToken) { | |
|
||
org.apache.shiro.authc.AuthenticationToken authToken = AuthenticationTokenHandler.extractShiroAuthToken(authenticationToken); | ||
|
||
// If already authenticated, do not check login info again | ||
/* | ||
TODO: understand potential repercussions in following situations: | ||
1. How to handle this in password change situations | ||
2. Can two subjects in same environment have same principal name? if so the following check is invalid | ||
*/ | ||
if (this.isAuthenticated() && this.getPrincipal().getName().equals(authToken.getPrincipal())) { | ||
return; | ||
} | ||
// Login via shiro realm. | ||
shiroSubject.login(authToken); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried replacing this line with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good find! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how important createSubject call after authenticate is. From skimming through it, it seems like it sets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The basic auth handling is taking too long which is leading to the build failures in tests that perform many async requests. The way to resolve it in the short-term is to disable identity when running the existing test suite in the gradle check. Long-term when security is merged into core, the existing tests in the gradle check should work with identity enabled when identity is promoted from sandbox. I'm not sure why the basic auth handling here is taking 500ms+ per request, but at least part of it is due to the bcrypt password matcher. The security plugin also performs bcrypt password matching and I am not sure how taxing basic auth is with the security plugin installed. |
||
} | ||
|
||
/** | ||
* A flag to indicate whether this subject is already authenticated | ||
* | ||
* @return true if authenticated, false otherwise | ||
*/ | ||
@Override | ||
public boolean isAuthenticated() { | ||
return shiroSubject.isAuthenticated(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* The OpenSearch Contributors require contributions made to | ||
* this file be licensed under the Apache-2.0 license or a | ||
* compatible open source license. | ||
*/ | ||
|
||
package org.opensearch.authn.internal; | ||
|
||
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; | ||
import org.apache.shiro.SecurityUtils; | ||
import org.apache.shiro.authc.AuthenticationException; | ||
import org.apache.shiro.subject.Subject; | ||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.opensearch.authn.tokens.AuthenticationToken; | ||
import org.opensearch.authn.tokens.BasicAuthToken; | ||
import org.opensearch.test.OpenSearchTestCase; | ||
|
||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.times; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
|
||
@ThreadLeakScope(ThreadLeakScope.Scope.NONE) | ||
public class InternalSubjectTests extends OpenSearchTestCase { | ||
private static final AuthenticationToken AUTH_TOKEN = new BasicAuthToken("Basic YWRtaW46YWRtaW4="); | ||
|
||
@Before | ||
public void initRealm() { | ||
new InternalAuthenticationManager(); | ||
} | ||
|
||
@After | ||
public void logoutSubject() { | ||
Subject subject = SecurityUtils.getSubject(); | ||
if (subject == null) return; | ||
if (subject.getSession() != null) subject.getSession().stop(); | ||
SecurityUtils.getSubject().logout(); | ||
} | ||
|
||
public void testGetPrincipal() { | ||
InternalSubject internalSubject = new InternalSubject(SecurityUtils.getSubject()); | ||
assertNull(internalSubject.getPrincipal()); | ||
|
||
internalSubject.login(AUTH_TOKEN); | ||
|
||
assertNotNull(internalSubject.getPrincipal()); | ||
} | ||
|
||
public void testLoginBehaviors() { | ||
Subject subject = mock(Subject.class); | ||
InternalSubject internalSubject = new InternalSubject(subject); | ||
|
||
// 1. Verify that login() is called on first attempt | ||
|
||
internalSubject.login(AUTH_TOKEN); | ||
verify(subject, times(1)).login(any()); | ||
|
||
// 2. Verify that call to login() is skipped on 2nd attempt for same user | ||
|
||
when(subject.isAuthenticated()).thenReturn(true); | ||
when(subject.getPrincipal()).thenReturn("admin"); | ||
|
||
internalSubject.login(AUTH_TOKEN); | ||
verify(subject, times(1)).login(any()); | ||
|
||
// 3. Verify that login() is called again for a different user | ||
|
||
when(subject.isAuthenticated()).thenReturn(true); | ||
when(subject.getPrincipal()).thenReturn("marvin"); | ||
|
||
// even though we are using same token, the mock stub returns different principal and hence login is called again | ||
internalSubject.login(AUTH_TOKEN); | ||
verify(subject, times(2)).login(any()); | ||
} | ||
|
||
public void testSuccessfulLoginAndLogOut() { | ||
InternalSubject internalSubject = new InternalSubject(SecurityUtils.getSubject()); | ||
|
||
internalSubject.login(AUTH_TOKEN); | ||
assertTrue(internalSubject.isAuthenticated()); | ||
} | ||
|
||
public void testLoginFailure() { | ||
InternalSubject internalSubject = new InternalSubject(SecurityUtils.getSubject()); | ||
|
||
AuthenticationToken authToken = new BasicAuthToken("Basic bWFydmluOmdhbGF4eQ=="); | ||
|
||
assertThrows(AuthenticationException.class, () -> internalSubject.login(authToken)); | ||
} | ||
|
||
public void testIsAuthenticated() { | ||
InternalSubject internalSubject = new InternalSubject(SecurityUtils.getSubject()); | ||
|
||
assertFalse(internalSubject.isAuthenticated()); | ||
internalSubject.login(AUTH_TOKEN); | ||
assertTrue(internalSubject.isAuthenticated()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Principal identifiers are unique within the same realm.
What is the purpose of the second part of this check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test would fail when:
admin
and isAuthenticated is set to truedummy
andadmin
and see that they don't match so incoming request should go through authentication workflowAlthough I'm not 100% sure about this behavior. How should
Subject
be treated for each incoming request?