Of course it depends on the certain situation but let me provide a couple of my subjective comments here:
I'm sure such cases should be avoided. The name of the method points that it just performs any operation like "Login". According to the method name we can't expect any result here. Is you'd like the method to return bool value it's much better to name it like IsLoggedIn(userName). In addition you'll never know if you need to extend the set of values being returned. So the enum is much better here also taking in account that the aim of the value is reflected in the enum name rather than simple bool.
The same as above. Exceptions here help to stop the whole execution hierarchy (which can of course contain more than 1 method in call stack) instead of just returning the result and let the caller to make appropriate decision. More flexible solution as for me. In the current case I'd use exceptions for parameters validation only. Situations like "wrong user name/password" are not exceptional. They are normal from the use cases point of view. null parameter or wrong parameter format are exceptional cases.
If you don't need the method to return a value, that is the way to go. Do not forget you shouldn't use exceptions as a navigation. I mean UserSuccessfullyCreatedException or so.
As I mentioned above, that is the best way as for me. The single point is not to place validation exceptions as a enum values. You have exceptions for it.
So enum result plus exceptions for validation is a way to go.
If you'd like to collect all the errors during the method execution you'll probably like to create special LoginOperationResult class to wrap all the information (including validation errors` occured during the method execution.
class OperationResult
{
public OperationStatus Status { get; set; }
public IEnumerable Errors { get; set; }
// or list of exceptions
}
class LoginOperationResult : OperationResult
{
// Login result specific data.
}
enum OperationStatus
{
Success,
Denied,
ValidationFailed,
// etc.
}