The rule of not taking a dependency is to simply pass it correctly, but from the point of view of your public API, this is not what you are doing. Since AccessGateKeeper is internal, it is not part of the public API - it is an implementation detail . This could be a private helper function of the UserAccessManagement class.
Thus, from a public point of view, the UserAccessManagement class UserAccessManagement not accept the dependency "just pass it". Instead, you can say that the UserAccessManagement class requires IUserRepository , IHashProvider and ITokenEncryptor .
However, from a support point, the current implementation is closely related to UserAccessManagement and AccessGateKeeper , which may or may not be a problem. However, if this is a problem, you might consider porting the desired behavior to the interface. Mechanical extraction may look like this:
public interface IAccess { void Grant(object ticket, string resource) }
Using this interface, you can change the implementation of UserAccessManagement to:
public class UserAccessManagement { private readonly IUserRepository _repo; private readonly IAccess _access; public UserAccessManagement(IUserRepository repo, IAccess access) { _repo = repo; _access = access; } public void GrantAccess(string username, string resource) { User user = repo.FindUser(username); _access.Grant(user.SpnTicket, resource); } }
An IAccess implementation might look like this:
public class Access : IAccess { private readonly IHashProvider _hash; private readonly ITokenEncryptor _tokenEnc; public Access(IHashProvider _hash, ITokenEncryptor _tokenEnc) { _hash = hash; _tokenEnc = tokenEnc; } public void Grant(object ticket, string resource) { new AccessGateKeeper(ticket, _hash, _tokenEnc) .GrantAccess(resource); } }