Skip to content

Commit

Permalink
Extract "createHashes" method for passwor update; simplify TokenAuthe…
Browse files Browse the repository at this point in the history
…nticator constructor
  • Loading branch information
Gene Gleyzer committed Jan 25, 2024
1 parent 21dff6b commit 395b4ee
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 19 deletions.
28 changes: 26 additions & 2 deletions lib_web/src/main/x/web/security/TokenAuthenticator.x
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,38 @@ import responses.SimpleResponse;
* (https://datatracker.ietf.org/doc/html/rfc6819.html).
*/
@Concurrent
service TokenAuthenticator(Realm realm, String apiName)
service TokenAuthenticator
implements Authenticator {

/**
* Construct the `TokenAuthenticator` for the specified [Realm]. If the `apiName` is not
* specified, the realm name will be used instead to validate the "Authorization" header.
*/
construct(Realm realm, String? apiName = Null) {
this.realm = realm;
this.apiName = apiName ?: realm.name;
}

assert() {
assert switch (apiName) {
case "Bearer",
"Basic",
"Digest": False;
default: True;
} as $"Reserved name {apiName}";
}

/**
* The Realm that contains the user/token information.
*/
public/private Realm realm;

/**
* The api name used in the "Authorization" header. Cannot be one of the reserved names, such as
* "Bearer", "Basic" or "Digest".
*/
String apiName;


// ----- Authenticator interface ---------------------------------------------------------------

Expand All @@ -34,7 +58,7 @@ service TokenAuthenticator(Realm realm, String apiName)
// "Authorization" header format: {apiName} {user}:{token}
Int userOffset = apiName.size;
if (CaseInsensitive.stringStartsWith(auth, apiName),
auth[userOffset] == ' ',
auth[userOffset] == ' ',
Int tokenOffset := auth.indexOf(':', userOffset)) {

String user = auth[userOffset >..< tokenOffset];
Expand Down
43 changes: 26 additions & 17 deletions lib_webauth/src/main/x/webauth/Users.x
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,31 @@ mixin Users
return False;
}

// hash the user and password data; this is performing the same work as Realm.userHash()
// and Realm.passwordHash() for each of the (up to) three supported algorithms
(HashInfo userHashes, HashInfo pwdHashes) = createHashes(realm, userName, password);

// look up the role names and convert them to role IDs
Int[] roleIds;
String[] roleNames = [roleName.is(String)?] : roleName;
AuthSchema schema = dbParent.as(AuthSchema);
if (Role[] roleList := schema.roles.findByNames(roleNames)) {
roleIds = roleList.map(r -> r.roleId, CollectImmutableArray.of(Int));
} else {
return False;
}

Int userId = schema.userId.next();
User user = new User(userId, userName, userHashes, pwdHashes, roleIds);
return putIfAbsent(userId, user)
? (True, user)
: False;
}

/**
* Hash the user and password data; this method is performing the same work as [Realm.userHash()]
* and [Realm.passwordHash()] for each of the (up to) three supported algorithms
*/
(HashInfo userHashes, HashInfo pwdHashes)
createHashes(Realm realm, String userName, String? password) {
Hash userBytes = $"{userName}:{realm.name}".utf8();
Hash pwdBytes = $"{userName}:{realm.name}:{password}".utf8();

Expand Down Expand Up @@ -74,21 +97,7 @@ mixin Users
sha512_256?.sign(pwdBytes).bytes : [],
);

// look up the role names and convert them to role IDs
Int[] roleIds;
String[] roleNames = [roleName.is(String)?] : roleName;
AuthSchema schema = dbParent.as(AuthSchema);
if (Role[] roleList := schema.roles.findByNames(roleNames)) {
roleIds = roleList.map(r -> r.roleId, CollectImmutableArray.of(Int));
} else {
return False;
}

Int userId = schema.userId.next();
User user = new User(userId, userName, userHashes, pwdHashes, roleIds);
return putIfAbsent(userId, user)
? (True, user)
: False;
return (userHashes, pwdHashes);
}

/**
Expand Down

0 comments on commit 395b4ee

Please sign in to comment.