Skip to content

Commit

Permalink
TokenManager Interface
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Crawford <[email protected]>
  • Loading branch information
stephen-crawford committed May 5, 2023
1 parent 9bf99b4 commit a73d42f
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 48 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class ShiroIdentityPlugin extends Plugin implements IdentityPlugin
private Logger log = LogManager.getLogger(this.getClass());

private final Settings settings;
private final AuthTokenHandler authTokenHandler;
private final ShiroTokenHandler authTokenHandler;

/**
* Create a new instance of the Shiro Identity Plugin
Expand All @@ -35,7 +35,7 @@ public final class ShiroIdentityPlugin extends Plugin implements IdentityPlugin
*/
public ShiroIdentityPlugin(final Settings settings) {
this.settings = settings;
authTokenHandler = new AuthTokenHandler();
authTokenHandler = new ShiroTokenHandler();

SecurityManager securityManager = new ShiroSecurityManager();
SecurityUtils.setSecurityManager(securityManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* @opensearch.experimental
*/
public class ShiroSubject implements Subject {
private final AuthTokenHandler authTokenHandler;
private final ShiroTokenHandler authTokenHandler;
private final org.apache.shiro.subject.Subject shiroSubject;

/**
Expand All @@ -29,7 +29,7 @@ public class ShiroSubject implements Subject {
* @param authTokenHandler Used to extract auth header info
* @param subject The specific subject being authc/z'd
*/
public ShiroSubject(final AuthTokenHandler authTokenHandler, final org.apache.shiro.subject.Subject subject) {
public ShiroSubject(final ShiroTokenHandler authTokenHandler, final org.apache.shiro.subject.Subject subject) {
this.authTokenHandler = Objects.requireNonNull(authTokenHandler);
this.shiroSubject = Objects.requireNonNull(subject);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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.identity.shiro;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Optional;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.opensearch.identity.Subject;
import org.opensearch.identity.tokens.AuthToken;
import org.opensearch.identity.tokens.BasicAuthToken;
import org.opensearch.identity.tokens.TokenManager;

/**
* Extracts Shiro's {@link AuthenticationToken} from different types of auth headers
*
* @opensearch.experimental
*/
class ShiroTokenHandler implements TokenManager {

/**
* Translates into shiro auth token from the given header token
* @param authenticationToken the token from which to translate
* @return An optional of the shiro auth token for login
*/
public Optional<AuthenticationToken> translateAuthToken(org.opensearch.identity.tokens.AuthToken authenticationToken) {
if (authenticationToken instanceof BasicAuthToken) {
final BasicAuthToken basicAuthToken = (BasicAuthToken) authenticationToken;
return Optional.of(new UsernamePasswordToken(basicAuthToken.getUser(), basicAuthToken.getPassword()));
}

return Optional.empty();
}

@Override
public AuthToken generateToken() {

Subject subject = new ShiroSubject(this, SecurityUtils.getSubject());
final byte[] rawEncoded = Base64.getEncoder().encode((subject.getPrincipal().getName() + ":" + generatePassword()).getBytes());
final String usernamePassword = new String(rawEncoded, StandardCharsets.UTF_8);
final String header = "Basic " + usernamePassword;

return new BasicAuthToken(header);
}

@Override
public boolean validateToken(AuthToken token) {
if (token instanceof BasicAuthToken) {
final BasicAuthToken basicAuthToken = (BasicAuthToken) token;
if (basicAuthToken.getUser().equals(SecurityUtils.getSubject()) && basicAuthToken.getPassword().equals(generatePassword())) {
return true;
}
}
return false;
}

@Override
public String getTokenInfo(AuthToken token) {
if (token instanceof BasicAuthToken) {
final BasicAuthToken basicAuthToken = (BasicAuthToken) token;
return basicAuthToken.toString();
}
throw new UnsupportedAuthenticationToken();
}

@Override
public void revokeToken(AuthToken token) {
if (token instanceof BasicAuthToken) {
final BasicAuthToken basicAuthToken = (BasicAuthToken) token;
basicAuthToken.revoke();
return;
}
throw new UnsupportedAuthenticationToken();
}

@Override
public void refreshToken(AuthToken token) {

}

public String generatePassword() {
return "superSecurePassword1!";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.opensearch.identity.tokens.AuthToken;
import org.opensearch.identity.tokens.BasicAuthToken;
import org.opensearch.identity.tokens.NoopToken;
import org.opensearch.test.OpenSearchTestCase;
import org.junit.Before;

Expand All @@ -23,11 +25,11 @@

public class AuthTokenHandlerTests extends OpenSearchTestCase {

private AuthTokenHandler authTokenHandler;
private ShiroTokenHandler authTokenHandler;

@Before
public void testSetup() {
authTokenHandler = new AuthTokenHandler();
authTokenHandler = new ShiroTokenHandler();
}

public void testShouldExtractBasicAuthTokenSuccessfully() {
Expand Down Expand Up @@ -59,4 +61,34 @@ public void testShouldReturnNullWhenExtractingNullToken() {

assertThat(translatedToken.isEmpty(), is(true));
}

public void testShouldRevokeTokenSuccessfully() {
final BasicAuthToken authToken = new BasicAuthToken("Basic dGVzdDp0ZTpzdA==");
assertTrue(authToken.toString().equals("Basic auth token with user=test, password=te:st"));
authTokenHandler.revokeToken(authToken);
assert(authToken.toString().equals("Basic auth token with user=, password="));
}

public void testShouldFailWhenRevokeToken() {
final NoopToken authToken = new NoopToken();
assert(authToken.getTokenIdentifier().equals("Noop"));
assertThrows(UnsupportedAuthenticationToken.class, () -> authTokenHandler.revokeToken(authToken));
}

public void testShouldGetTokenInfoSuccessfully() {
final BasicAuthToken authToken = new BasicAuthToken("Basic dGVzdDp0ZTpzdA==");
assert(authToken.toString().equals(authTokenHandler.getTokenInfo(authToken)));
}

public void testShouldFailGetTokenInfo() {
final NoopToken authToken = new NoopToken();
assert(authToken.getTokenIdentifier().equals("Noop"));
assertThrows(UnsupportedAuthenticationToken.class, () -> authTokenHandler.getTokenInfo(authToken));
}


public void testShouldFailValidateToken() {
final AuthToken authToken = new NoopToken();
assertFalse(authTokenHandler.validateToken(authToken));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
public class ShiroSubjectTests extends OpenSearchTestCase {

private org.apache.shiro.subject.Subject shiroSubject;
private AuthTokenHandler authTokenHandler;
private ShiroTokenHandler authTokenHandler;
private ShiroSubject subject;

@Before
public void setup() {
shiroSubject = mock(org.apache.shiro.subject.Subject.class);
authTokenHandler = mock(AuthTokenHandler.class);
authTokenHandler = mock(ShiroTokenHandler.class);
subject = new ShiroSubject(authTokenHandler, shiroSubject);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.identity.noop;

import org.opensearch.identity.tokens.AuthToken;
import org.opensearch.identity.tokens.NoopToken;
import org.opensearch.identity.tokens.TokenManager;

public class NoopTokenManager implements TokenManager {
@Override
public AuthToken generateToken() {
return new NoopToken();
}

@Override
public boolean validateToken(AuthToken token) {
if (token instanceof NoopToken){
return true;
}
return false;
}

@Override
public String getTokenInfo(AuthToken token) {
return "Token is NoopToken";
}

@Override
public void revokeToken(AuthToken token) {

}

@Override
public void refreshToken(AuthToken token) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
*/
public final class BasicAuthToken implements AuthToken {

public final static String TOKEN_IDENIFIER = "Basic";
public final static String TOKEN_IDENTIFIER = "Basic";

private String user;
private String password;

public BasicAuthToken(final String headerValue) {
final String base64Encoded = headerValue.substring(TOKEN_IDENIFIER.length()).trim();
final String base64Encoded = headerValue.substring(TOKEN_IDENTIFIER.length()).trim();
final byte[] rawDecoded = Base64.getDecoder().decode(base64Encoded);
final String usernamepassword = new String(rawDecoded, StandardCharsets.UTF_8);

Expand All @@ -41,4 +41,14 @@ public String getUser() {
public String getPassword() {
return password;
}

@Override
public String toString(){
return "Basic auth token with user=" + user + ", password=" + password;
}

public void revoke() {
this.password="";
this.user="";
}
}
18 changes: 18 additions & 0 deletions server/src/main/java/org/opensearch/identity/tokens/NoopToken.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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.identity.tokens;

public class NoopToken implements AuthToken {
public final static String TOKEN_IDENTIFIER = "Noop";

public String getTokenIdentifier() {
return TOKEN_IDENTIFIER;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static AuthToken extractToken(final RestRequest request) {
if (authHeaderValue.isPresent()) {
final String authHeaderValueStr = authHeaderValue.get();

if (authHeaderValueStr.startsWith(BasicAuthToken.TOKEN_IDENIFIER)) {
if (authHeaderValueStr.startsWith(BasicAuthToken.TOKEN_IDENTIFIER)) {
return new BasicAuthToken(authHeaderValueStr);
} else {
if (logger.isDebugEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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.identity.tokens;

public interface TokenManager {

public AuthToken generateToken();

public boolean validateToken(AuthToken token);

public String getTokenInfo(AuthToken token);

public void revokeToken(AuthToken token);

public void refreshToken(AuthToken token);
}

0 comments on commit a73d42f

Please sign in to comment.