We’ve developed some resources to help you work effectively from home during COVID-19 Click here to learn more

The pipeline

In this article
    NetServer contains seven (7) different plugins, for as many different ways of authenticating
    • SoCredentials (ticket string)
    • Username+password (superoffice user, not AD)
    • Windows/AD user, who is a person (not System, Guest etc)
    • Impersonation identity
    • Anonymous identity
    • Username+password, matched against Windows/AD
    • Windows/AD user, who is not a person

    The plugins are called in this order. Each plugin is given all the available evidence (credentials)

    In the future, they can be useful in many possible scenarios. For a Web Server, the IP address the request is coming from is a piece of evidence that can be taken into account. If a certain IP range is prohibited, then the check can refuse login right there. Or time of day... or whatever. You can write all sorts of funny rules into your plugins; overdoing it is easy and leads to major frustration if your policies are too draconian.
    The post-vote is also interesting - for instance, one could have a policy saying that certain users are only allowed to log on during normal working hours. A plugin would then take the resolved identity, look at the clock and then vote.

    Each plugin looks for credentials it understands

    • Such credentials are evaluated, for instance, a password is checked against stored information
    • Success results in an associate id

    The first one to resolve the identity breaks the loop.
    "Expensive" plugins should come late in the order!   Expensive = any kind of Internet lookup
    You may be used to having the Internet a few milliseconds away. But - especially on a laptop in some odd place - it may look like you have connectivity, but not have it; or you may have connectivity, but it's slow or blocked. Unless you aboslutely need to look up something, don't; and do put such plugins at the end of the queue.

    Post Validator

    Each plugin can have a post-validator
    Post-validators are called after a plugin resolves an identity
    Post-validators can block login if specific conditions are not met

    • This can be used to block based on any available knowledge.

    The full potential of this system is not yet leveraged
    Possible use-case: block certain authentication methods based on IP ranges (can't use method X if you're on an outside network).

    Authentication Pipeline Source Code

    This is the actual source code (stripped of comments to make it fit) of the authentication pipeline in NetServer. Included here so you can see what actually happens during authentication; a block of code equals any number of hand-waving words


                List<SecurityToken> tokenList = new List<SecurityToken>(Tokens);
                ISoSecurityTokenValidator[] preValidators = PluginFactory.Create<ISoSecurityTokenValidator>();
                string reason = null;
                foreach (ISoSecurityTokenValidator validator in preValidators)
                {
                    if (validator.TryValidateTokens(tokenList, out reason) == TokenValidationResult.Rejected)
                        throw new SoSessionException("Failed to validate tokens: " + reason);
                }

                ISoIdentityResolver[] resolvers = PluginFactory.Create<ISoIdentityResolver>();
                ISoIdentityValidator[] postValidators = PluginFactory.Create<ISoIdentityValidator>();

                List<string> reasons = new List<string>();
                foreach (ISoIdentityResolver resolver in resolvers)
                {
                    ISoIdentity identity = resolver.ResolveIdentity(tokenList, dbConnection);
                    if (identity != null)
                    {
                        bool isValid = false;
                        bool isRejected = false;
                        foreach (ISoIdentityValidator validator in postValidators)
                        {
                            //string reason = null;
                            switch (validator.TryValidateIdentity(tokenList, identity, dbConnection, out reason))
                            {
                                case TokenValidationResult.Valid:
                                    isValid = true;
                                    break;
                                case TokenValidationResult.Rejected:
                                    isRejected = true;
                                    reasons.Add(reason);
                                    continue;
                            }
                        }
                        if (isRejected)
                            continue;
                        if (isValid)
                            return identity;
                    }
                }