acejazz
acejazz

Reputation: 819

If the authentication involves some business logic, shouldn't it go to a Domain Service?

I'm reading "Implementing Domain Driven Design" by Vaughn Vernon and there is an excerpt that sounds quite wrong to me. In the chapter related to Services, we are trying to model a business specific authentication process:

boolean authentic = false;
Tenant tenant = DomainRegistry
    .tenantRepository()
    .tenantOfId(aTenantId);

if (tenant != null && tenant.isActive()) {
    User user = DomainRegistry
        .userRepository()
        .userWithUsername(aTenantId, aUsername);

    if (user != null) {
        authentic = tenant.authenticate(user, aPassword);
    }
}

return authentic;

Immediately after we have:

Look at the additional burden that we've heaped on the client. It now needs to understand much more about authentication than it should.

And a bit later we have:

The only business responsibility that the client should have is to coordinate the use of a single domain-specific operation that handles all other details of the business problem.

Following by:

UserDescriptor userDescriptor =
    DomainRegistry
       .authenticationService()
       .authenticate(aTenantId, aUsername, aPassword);

And so far this makes completely sense to me.

Couple of pages later, referring to the same example, though, the book states:

[...] you may decide to place this somewhat technical implementation class in a location outside the domain model. Technical implementation may be housed in a Module in the Infrastructure Layer, for example.

And this makes also sense to me.

But, the following code is this:

package com.saasovation.identityaccess.infrastructure.services;

// ...

public class DefaultEncryptionAuthenticationService implements AuthenticationService {
    // ...
    @Override
    public UserDescriptor authenticate(
            TenantId aTenantId,
            String aUsername,
            String aPassword) {
        // Guards here
        UserDescriptor userDescriptor = null;

        Tenant tenant = DomainRegistry
            .tenantRepository()
            .tenantOfId(aTenantId);

        if (tenant != null && tenant.isActive()) {
            String encryptedPassword =
                DomainRegistry
                    .encryptionService()
                    .encryptedValue(aPassword);

            User user =
                DomainRegistry
                    .userRepository()
                    .userFromAuthenticCredentials(
                        aTenantId,
                        aUsername,
                        encryptedPassword);

             if (user != null && user.isEnabled()) {
                 userDescriptor = user.userDescriptor();
             }
        
    }
    return userDescriptor;
}

and this is what I don't understand. The Service, including the aforementioned business logic (plus some more details, that is, encryption) is placed in the Infrastructure Layer (see package name), which is a client of the Domain Model. This means that eventually the previous condition is not met:

Look at the additional burden that we've heaped on the client. It now needs to understand much more about authentication than it should.

Shouldn't this Service be placed in the Domain layer? What makes it an Infrastructure Layer? Isn't the Infrastructure Layer considered a client for the Domain Layer, assuming we are using Hexagonal Architecture, as the book is actually doing?

Upvotes: 0

Views: 466

Answers (2)

desertech
desertech

Reputation: 1029

Infrastructural components are not clients of the domain layer, they are implementations of domain abstractions.

By "client", the author of the book probably refers to whoever invokes the domain (business) operation.

Generally speaking, authentication can be implemented in various ways, so it makes sense to put one implementation or another in infrastructure layer; but authentication AS CONCEPT is considered to be a domain abstraction (e.g. interface), as expressed in the following line of code:

DomainRegistry.authenticationService()

Still, though, the example of DefaultEncryptionAuthenticationService is somewhat obscure to me. Package name indeed implies infrastructure, however implementation involves several abstracted services (tenant, user, encryption) and some business logic, which means we are actually dealing with a domain service.

(To better understand how abstractions and implementations play together, it is important to understand the dependency inversion principle).

Upvotes: 2

plalx
plalx

Reputation: 43718

I don't recall that specific book sample, but whether or not logic is considered domain logic depends on the context. For instance, encryption may be a domain concern in the context of a cryptography library, but an infrastructure concern in some other context.

When the context is not clearly defined then the line between domain & infrastructure become can be blurry.

If we look at the IDDD's repository, we can see that the AuthenticationService is considered a domain concern (like you'd expect) in the Identity & Access bounded context.

Upvotes: 0

Related Questions