Skip to content
This repository has been archived by the owner on May 10, 2022. It is now read-only.

Commit

Permalink
feat(security): handle challenge from server (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
levy5307 authored Nov 27, 2020
1 parent 5aa92a0 commit befbf8b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,24 @@ public void run() {
TimeUnit.MILLISECONDS);
}

public void onAuthSucceed() {
Queue<RequestEntry> swappedPendingSend = new LinkedList<>();
synchronized (authPendingSend) {
authSucceed = true;
swappedPendingSend.addAll(authPendingSend);
authPendingSend.clear();
}

while (!swappedPendingSend.isEmpty()) {
RequestEntry e = swappedPendingSend.poll();
if (pendingResponse.get(e.sequenceId) != null) {
write(e, fields);
} else {
logger.info("{}: {} is removed from pending, perhaps timeout", name(), e.sequenceId);
}
}
}

// return value:
// true - pend succeed
// false - pend failed
Expand Down
24 changes: 22 additions & 2 deletions src/main/java/com/xiaomi/infra/pegasus/security/Negotiation.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Negotiation {
private static final List<String> expectedMechanisms = Collections.singletonList("GSSAPI");

private negotiation_status status;
private ReplicaSession session;
ReplicaSession session;
SaslWrapper saslWrapper;

Negotiation(ReplicaSession session, Subject subject, String serviceName, String serviceFQDN) {
Expand Down Expand Up @@ -95,7 +95,7 @@ private void handleResponse() throws Exception {
break;
case SASL_INITIATE:
case SASL_CHALLENGE_RESP:
// TBD(zlw):
onChallenge(resp);
break;
default:
throw new Exception("unexpected negotiation status: " + resp.status);
Expand Down Expand Up @@ -125,6 +125,21 @@ void onMechanismSelected(negotiation_response response) throws Exception {
send(status, msg);
}

void onChallenge(negotiation_response response) throws Exception {
switch (response.status) {
case SASL_CHALLENGE:
blob msg = saslWrapper.evaluateChallenge(response.msg.data);
status = negotiation_status.SASL_CHALLENGE_RESP;
send(status, msg);
break;
case SASL_SUCC:
negotiationSucceed();
break;
default:
throw new Exception("receive wrong negotiation msg type" + response.status.toString());
}
}

public String getMatchMechanism(String respString) {
String matchMechanism = "";
String[] serverSupportMechanisms = respString.split(",");
Expand All @@ -150,6 +165,11 @@ private void negotiationFailed() {
session.closeSession();
}

private void negotiationSucceed() {
status = negotiation_status.SASL_SUCC;
session.onAuthSucceed();
}

negotiation_status getStatus() {
return status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ public blob getInitialResponse() throws PrivilegedActionException {
}
});
}

// If a challenge is received from the server during the authentication process,
// this method is called to prepare an appropriate next response to submit to the server.
public blob evaluateChallenge(final byte[] data) throws PrivilegedActionException {
return Subject.doAs(
subject,
(PrivilegedExceptionAction<blob>) () -> new blob(saslClient.evaluateChallenge(data)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.xiaomi.infra.pegasus.apps.negotiation_response;
import com.xiaomi.infra.pegasus.apps.negotiation_status;
import com.xiaomi.infra.pegasus.base.blob;
import com.xiaomi.infra.pegasus.rpc.async.ReplicaSession;
import java.nio.charset.Charset;
import javax.security.auth.Subject;
import org.junit.Assert;
Expand Down Expand Up @@ -134,4 +135,45 @@ public void testMechanismSelected() {
response.status = negotiation_status.SASL_LIST_MECHANISMS;
Assertions.assertThrows(Exception.class, () -> mockNegotiation.onMechanismSelected(response));
}

@Test
public void testChallenge() {
Negotiation mockNegotiation = Mockito.spy(negotiation);
SaslWrapper mockSaslWrapper = Mockito.mock(SaslWrapper.class);
ReplicaSession mockSession = Mockito.mock(ReplicaSession.class);
mockNegotiation.saslWrapper = mockSaslWrapper;
mockNegotiation.session = mockSession;

// mock operation
Mockito.doNothing().when(mockNegotiation).send(any(), any());
Mockito.doNothing().when(mockNegotiation.session).onAuthSucceed();
try {
Mockito.when(mockNegotiation.saslWrapper.evaluateChallenge(any())).thenReturn(new blob());
} catch (Exception ex) {
Assert.fail();
}

// normal case
Assertions.assertDoesNotThrow(
() -> {
negotiation_response response =
new negotiation_response(negotiation_status.SASL_CHALLENGE, new blob(new byte[0]));
mockNegotiation.onChallenge(response);
Assert.assertEquals(mockNegotiation.getStatus(), negotiation_status.SASL_CHALLENGE_RESP);

response = new negotiation_response(negotiation_status.SASL_SUCC, new blob(new byte[0]));
mockNegotiation.onChallenge(response);
Assert.assertEquals(mockNegotiation.getStatus(), negotiation_status.SASL_SUCC);
});

// deal with wrong response.status
Assertions.assertThrows(
Exception.class,
() -> {
negotiation_response response =
new negotiation_response(
negotiation_status.SASL_LIST_MECHANISMS, new blob(new byte[0]));
mockNegotiation.onChallenge(response);
});
}
}

0 comments on commit befbf8b

Please sign in to comment.