0

I'm learning about how authentication works using the Aqueduct framework.

In my channel.dart file I have a route:

router
  .route('/protected') 
  .link(() => Authorizer.basic(validator))
  .link(() => ProtectedController()); 

But I don't know how to create the validator. In the docs I see that I can make a custom Authorizer without using an AuthServer. The code example is this:

class BasicValidator implements AuthValidator {
  @override
  FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {}
    var user = await userForName(usernameAndPassword.username);
    if (user.password == hash(usernameAndPassword.password, user.salt)) {
      return Authorization(...);
    }

    return null;
  }
}

I'd like to make a basic working example, but this is the closest that I could get:

class BasicValidator implements AuthValidator {
  @override
  FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {

    final validUsername = 'bob';
    final validPassword = 'password123';

    // How do I get the parsed username?
    // How do I get the parsed password?

    if (parsedUsername == validUsername && parsedPassword == validPassword) {
      // How do I create an Authorization?
      return Authorization(...);
    }

    return null;
  }

  // What is this?
  @override
  List<APISecurityRequirement> documentRequirementsForAuthorizer(APIDocumentContext context, Authorizer authorizer, {List<AuthScope> scopes}) {
    return null;
  }
}

Could anyone show me a basic working example of Basic authorization validator?

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393

1 Answers1

1

authorizationData is an instance of AuthBasicCredentials when using Authorizer.basic. An object of this type has username and password fields derived from parsing the 'Authorization' header from a request.

An Authorization object is a container for data related to the authorized resource owner (such as their user ID). It is used by subsequent controllers to control authorization without having to look up the authorized user again; you should populate it with any authorization information you have available.

documentRequirementsForAuthorizer is used during OpenAPI document generation. An Authorizer that uses your validator will encode the returned security requirements into the OpenAPI operations being secured.

See also http://aqueduct.io/docs/auth/authorizer/#using-authorizers-without-authserver.

@override
FutureOr<Authorization> validate<T>(AuthorizationParser<T> parser, T authorizationData, {List<AuthScope> requiredScope}) {

    final validUsername = 'bob';
    final validPassword = 'password123';

    final credentials = authorizationData as AuthBasicCredentials;

    if (credentials.username == validUsername 
    && credentials.password == validPassword) {

      return Authorization(
       null, // no client ID for basic auth 
       await getUserIDFromUsername(validUsername), // This is your problem to solve
       this, // always this
       credentials: credentials // if you want to pass this info along 
       );
    }

    return null;
  }
Joe Conway
  • 1,566
  • 9
  • 8
  • If I'm not using OpenAPI documentation (yet), is `null` the most secure default return value for `documentRequirementsForAuthorizer`? – Suragch Apr 29 '19 at 20:38
  • Also, the docs example shows a `hash()` function. Is that in some library or do I need to implement it myself? – Suragch Apr 29 '19 at 21:25
  • Regarding my second question, I see there is a `AuthUtility.generatePasswordHash()` function. – Suragch Apr 29 '19 at 22:30