Skip to content

Commit

Permalink
Merge pull request #118 from muzzammilshahid/send-abort
Browse files Browse the repository at this point in the history
Send Abort if authentication fails
  • Loading branch information
muzzammilshahid authored Jul 22, 2024
2 parents 4df984b + 349c4fb commit 2c3a93b
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 56 deletions.
39 changes: 35 additions & 4 deletions lib/src/acceptor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ class Acceptor {
switch (method) {
case anonymous:
AnonymousRequest request = AnonymousRequest(msg.realm, msg.authID, msg.authExtra);
Response response = _authenticator.authenticate(request);
Response response;
try {
response = _authenticator.authenticate(request);
} on Exception catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
} on Error catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
}

_state = stateWelcomeSent;

Welcome welcome = Welcome(_sessionID, routerRoles, response.authID, response.authRole, method, authExtra: {});
Expand All @@ -86,7 +94,14 @@ class Acceptor {

String publicKey = msg.authExtra["pubkey"];
CryptoSignRequest request = CryptoSignRequest(msg.realm, msg.authID, msg.authExtra, publicKey);
_response = _authenticator.authenticate(request);
try {
_response = _authenticator.authenticate(request);
} on Exception catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
} on Error catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
}

_publicKey = publicKey;

String challenge = generateCryptoSignChallenge();
Expand All @@ -96,7 +111,15 @@ class Acceptor {

case wampcra:
WAMPCRARequest request = WAMPCRARequest(msg.realm, msg.authID, msg.authExtra);
Response response = _authenticator.authenticate(request);
Response response;
try {
response = _authenticator.authenticate(request);
} on Exception catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
} on Error catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
}

if (response is! WAMPCRAResponse) {
throw Exception("invalid response type for WAMPCRA");
}
Expand Down Expand Up @@ -154,7 +177,15 @@ class Acceptor {

case ticket:
TicketRequest request = TicketRequest(_hello.realm, _hello.authID, _hello.authExtra, msg.signature);
Response response = _authenticator.authenticate(request);
Response response;
try {
response = _authenticator.authenticate(request);
} on Exception catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
} on Error catch (e) {
return Abort({}, errAuthenticationFailed, args: [e.toString()]);
}

_state = stateWelcomeSent;

Welcome welcome = Welcome(_sessionID, routerRoles, response.authID, response.authRole, ticket, authExtra: {});
Expand Down
222 changes: 170 additions & 52 deletions test/joiner_acceptor_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,90 +6,208 @@ import "package:wampproto/joiner.dart";
import "package:wampproto/messages.dart";
import "package:wampproto/serializers.dart";

const realm = "realm1";
const authID = "foo";
const ticket = "fooTicket";
const secret = "barSecret";
const privateKey = "175604dcce3944595dad640da1676d5e1e1a3950f872f177b1269981140f1c5d";
const publicKey = "8096cadfd3af87662d4c6589605801c1e2841c4e2cf3d6c30fb187c09c76c5ac";
final authenticator = Authenticator();

// Custom authenticator implementation
class Authenticator extends IServerAuthenticator {
@override
Response authenticate(Request request) {
switch (request.method) {
case "anonymous":
if (request is AnonymousRequest) {
if (request.realm == realm && request.authID == authID) {
return Response(request.authID, "anonymous");
case "ticket":
}

throw Exception("invalid realm");
} else if (request is TicketRequest) {
if (request.ticket == ticket) {
return Response(request.authID, "anonymous");
case "wampcra":
return WAMPCRAResponse(request.authID, "anonymous", "password");
case "cryptosign":
}

throw Exception("invalid ticket");
} else if (request is WAMPCRARequest) {
if (request.realm == realm && request.authID == authID) {
return WAMPCRAResponse(request.authID, "anonymous", secret);
}

throw Exception("invalid authID");
} else if (request is CryptoSignRequest) {
if (request.publicKey == publicKey) {
return Response(request.authID, "anonymous");
}

default:
throw ArgumentError("invalid auth method");
throw Exception("unknown publikey");
}
throw Exception("invalid auth method");
}

@override
List<String> methods() {
return ["cryptosign", "ticket", "wampcra", "anonymous"];
}
List<String> methods() => ["cryptosign", "ticket", "wampcra", "anonymous"];
}

const realm = "realm1";

void main() {
var authenticator = Authenticator();
test("AnonymousAuth", () {
var serializer = JSONSerializer();
var joiner = Joiner(realm, serializer: serializer, authenticator: AnonymousAuthenticator(""));
var acceptor = Acceptor(serializer: serializer, authenticator: authenticator);

var hello = joiner.sendHello();
group("Authentication Tests", () {
group("AnonymousAuth", () {
test("JSONSerializer", () {
final serializer = JSONSerializer();
testAnonymousAuth(serializer);
});

test("CBORSerializer", () {
final serializer = CBORSerializer();
testAnonymousAuth(serializer);
});

test("MsgPackSerializer", () {
final serializer = JSONSerializer();
testAnonymousAuth(serializer);
});
});

group("TicketAuth", () {
test("JSONSerializer", () {
var ticketAuthenticator = TicketAuthenticator(ticket, authID);
final serializer = JSONSerializer();
testAuth(ticketAuthenticator, serializer);
});

test("CBORSerializer", () {
var ticketAuthenticator = TicketAuthenticator(ticket, authID);
final serializer = CBORSerializer();
testAuth(ticketAuthenticator, serializer);
});

test("MsgPackSerializer", () {
var ticketAuthenticator = TicketAuthenticator(ticket, authID);
final serializer = MsgPackSerializer();
testAuth(ticketAuthenticator, serializer);
});

test("InvalidTicket", () {
var ticketAuthenticator = TicketAuthenticator("invalid", authID);
final serializer = JSONSerializer();
expect(() => testAuth(ticketAuthenticator, serializer), throwsException);
});
});

group("CRAAuth", () {
test("JSONSerializer", () {
var craAuthenticator = WAMPCRAAuthenticator(secret, authID, {"challenge": "test"});
final serializer = JSONSerializer();
testAuth(craAuthenticator, serializer);
});

test("CBORSerializer", () {
var craAuthenticator = WAMPCRAAuthenticator(secret, authID, {"challenge": "test"});
final serializer = CBORSerializer();
testAuth(craAuthenticator, serializer);
});

test("MsgPackSerializer", () {
var craAuthenticator = WAMPCRAAuthenticator(secret, authID, {"challenge": "test"});
final serializer = MsgPackSerializer();
testAuth(craAuthenticator, serializer);
});

test("InvalidSecret", () {
var craAuthenticator = WAMPCRAAuthenticator("invalid", authID, {"challenge": "test"});
final serializer = JSONSerializer();
expect(() => testAuth(craAuthenticator, serializer), throwsException);
});

test("InvalidAuthID", () {
var craAuthenticator = WAMPCRAAuthenticator(secret, "invalid", {"challenge": "test"});
final serializer = JSONSerializer();
expect(() => testAuth(craAuthenticator, serializer), throwsException);
});
});

group("CryptoSignAuth", () {
test("JSONSerializer", () {
var cryptoSignAuthenticator = CryptoSignAuthenticator(authID, privateKey);
final serializer = JSONSerializer();
testAuth(cryptoSignAuthenticator, serializer);
});

test("CBORSerializer", () {
var cryptoSignAuthenticator = CryptoSignAuthenticator(authID, privateKey);
final serializer = CBORSerializer();
testAuth(cryptoSignAuthenticator, serializer);
});

test("MsgPackSerializer", () {
var cryptoSignAuthenticator = CryptoSignAuthenticator(authID, privateKey);
final serializer = MsgPackSerializer();
testAuth(cryptoSignAuthenticator, serializer);
});

test("InvalidKey", () {
var cryptoSignAuthenticator =
CryptoSignAuthenticator(authID, "2e9bef98114241d2226996cf09faf87dad892643a7c5fde186783470bce21df3");
final serializer = JSONSerializer();
expect(() => testAuth(cryptoSignAuthenticator, serializer), throwsException);
});
});
});
}

var welcomeMap = acceptor.receive(hello);
var welcome = serializer.deserialize(welcomeMap.key);
expect(welcome, isA<Welcome>());
expect(welcomeMap.value, true);
void testAnonymousAuth(Serializer serializer) {
var anonymousAuthenticator = AnonymousAuthenticator(authID);
final joiner = Joiner(realm, serializer: serializer, authenticator: anonymousAuthenticator);
final acceptor = Acceptor(serializer: serializer, authenticator: authenticator);

var welcomeJoiner = joiner.receive(welcomeMap.key);
expect(welcomeJoiner, null);
final hello = joiner.sendHello();

var sessionDetails = joiner.getSessionDetails();
expect(sessionDetails, isNotNull);
});
// Process and verify the HELLO message
final welcomeMap = acceptor.receive(hello);
final welcome = serializer.deserialize(welcomeMap.key);

test("TicketAuth", () => testAuth(authenticator, TicketAuthenticator("", "test")));
expect(welcome, isA<Welcome>());
expect(welcomeMap.value, true);

test("CRAAuth", () => testAuth(authenticator, WAMPCRAAuthenticator("password", "test", {"challenge": "test"})));
// Ensure no additional messages are received
final payload = joiner.receive(welcomeMap.key);
expect(payload, null);

test(
"CryptoSignAuth",
() => testAuth(
authenticator,
CryptoSignAuthenticator("authID", "6d9b906ad60d1f4dd796dbadcc2e2252310565ccdc6fe10b289df5684faf2a46"),
),
);
// Verify session details are available
final sessionDetails = joiner.getSessionDetails();
expect(sessionDetails, isNotNull);
}

void testAuth(Authenticator authenticator, IClientAuthenticator clientAuthenticator) {
var serializer = JSONSerializer();
var joiner = Joiner(realm, serializer: serializer, authenticator: clientAuthenticator);
var acceptor = Acceptor(serializer: serializer, authenticator: authenticator);
void testAuth(IClientAuthenticator clientAuthenticator, Serializer serializer) {
final joiner = Joiner(realm, serializer: serializer, authenticator: clientAuthenticator);
final acceptor = Acceptor(serializer: serializer, authenticator: authenticator);

var hello = joiner.sendHello();
final hello = joiner.sendHello();

// Process and verify the CHALLENGE message
final challengeMap = acceptor.receive(hello);
final challenge = serializer.deserialize(challengeMap.key);

var challengeMap = acceptor.receive(hello);
var challenge = serializer.deserialize(challengeMap.key);
expect(challenge, isA<Challenge>());
expect(challengeMap.value, false);

var authenticated = joiner.receive(challengeMap.key);
// Authenticate and verify the response
final authenticated = joiner.receive(challengeMap.key);
expect(authenticated, isNotNull);

var welcomeMap = acceptor.receive(authenticated!);
var welcome = serializer.deserialize(welcomeMap.key);
// Process and verify the WELCOME message
final welcomeMap = acceptor.receive(authenticated!);
final welcome = serializer.deserialize(welcomeMap.key);

expect(welcome, isA<Welcome>());
expect(welcomeMap.value, true);

var welcomeJoiner = joiner.receive(welcomeMap.key);
expect(welcomeJoiner, null);
expect(joiner.getSessionDetails(), isNotNull);
// Ensure no additional messages are received
final payload = joiner.receive(welcomeMap.key);
expect(payload, null);

var sessionDetails = joiner.getSessionDetails();
// Verify session details are available
final sessionDetails = joiner.getSessionDetails();
expect(sessionDetails, isNotNull);
}

0 comments on commit 2c3a93b

Please sign in to comment.