< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Security.LdapSettings
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/LdapSettings.cs
Line coverage
56%
Covered lines: 28
Uncovered lines: 22
Coverable lines: 50
Total lines: 200
Line coverage: 56%
Branch coverage
44%
Covered branches: 8
Total branches: 18
Branch coverage: 44.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
.ctor(...)100%110%
.ctor(...)100%11100%
.ctor(...)100%11100%
Validate()66.66%121262.5%
ConnectLDAP()0%440%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Security/LdapSettings.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.ComponentModel;
 7using System.DirectoryServices.Protocols;
 8using System.Net;
 9using Microsoft.Extensions.Caching.Memory;
 10
 11namespace CoreWCF.Security
 12{
 13    public class LdapSettings
 14    {
 15        private LdapConnection _ldapConnection;
 16        /// <summary>
 17        /// Default constructor.
 18        /// </summary>
 19        /// <param name="servers">List of ldap servers</param>
 20        /// <param name="domain">domain name to search for</param>
 21        /// <param name="orgUnit"> org unit to search for. This is required per the issue https://github.com/dotnet/runt
 922        public LdapSettings(string server, string domain, string orgUnit) : this(new string[] { server }, domain, orgUni
 23        {
 924        }
 25
 26        /// <summary>
 27        /// Constructor.
 28        /// </summary>
 29        /// <param name="server"></param>
 30        /// <param name="domain"></param>
 31        /// <param name="machineAccountName"></param>
 32        /// <param name="machineAccountPassword"></param>
 33        /// <param name="orgUnit"></param>
 34        public LdapSettings(string server, string domain, string machineAccountName, string machineAccountPassword, stri
 035            : this(new string[] { server }, domain, machineAccountName, machineAccountPassword, orgUnit)
 36        {
 37
 038        }
 39        /// <summary>
 40        /// Default constructor.
 41        /// </summary>
 42        /// <param name="servers">List of ldap servers</param>
 43        /// <param name="domain">domain name to search for</param>
 44        /// <param name="orgUnit"> This is required </param>
 945        public LdapSettings(string[] servers, string domain, string orgUnit) : this(servers, domain, null, null, orgUnit
 46        {
 47
 948        }
 49
 50        /// <summary>
 51        /// Constructor to pass machine account name and machine account password.
 52        /// </summary>
 53        /// <param name="servers"></param>
 54        /// <param name="domain"></param>
 55        /// <param name="machineAccountName"></param>
 56        /// <param name="machineAccountPassword"></param>
 957        public LdapSettings(string[] servers, string domain, string machineAccountName, string machineAccountPassword, s
 58        {
 959            Servers = servers;
 960            Domain = domain;
 961            MachineAccountName = machineAccountName;
 962            MachineAccountPassword = machineAccountPassword;
 963            OrgUnit = orgUnit;
 964            Validate();
 965            EnableLdapClaimResolution = true;
 966            ClaimsCache = new MemoryCache(new MemoryCacheOptions { SizeLimit = ClaimsCacheSize });
 967        }
 68
 69        /// <summary>
 70        /// list of servers for ldap search
 71        /// </summary>
 1872        public string[] Servers { get; }
 73        /// <summary>
 74        /// Configure whether LDAP connection should be used to resolve claims.
 75        /// This is mainly used on Linux.
 76        /// </summary>
 77        [DefaultValue(true)]
 2778        public bool EnableLdapClaimResolution { get; set; }
 79
 80        /// <summary>
 81        /// The domain to use for the LDAP connection. This is a mandatory setting.
 82        /// </summary>
 83        /// <example>
 84        /// DOMAIN.com
 85        /// </example>
 986        public string Domain { get; }
 87
 88        /// <summary>
 89        /// Organization unit to start with. If not provided, it will search from top domain.
 90        /// </summary>
 091        public string OrgUnit { get; }
 92
 93        /// <summary>
 94        /// The machine account name to use when opening the LDAP connection.
 95        /// If this is not provided, the machine wide credentials of the
 96        /// domain joined machine will be used.
 97        /// </summary>
 998        public string MachineAccountName { get; }
 99
 100        /// <summary>
 101        /// The machine account password to use when opening the LDAP connection.
 102        /// This must be provided if a <see cref="MachineAccountName"/> is provided.
 103        /// </summary>
 9104        public string MachineAccountPassword { get; }
 105
 106        /// <summary>
 107        /// This option indicates whether nested groups should be ignored when
 108        /// resolving Roles. The default is false.
 109        /// </summary>
 0110        public bool IgnoreNestedGroups { get; set; }
 111
 112        /// <summary>
 113        /// The <see cref="LdapConnection"/> to be used to retrieve role claims.
 114        /// If no explicit connection is provided, an LDAP connection will be
 115        /// automatically created based on the <see cref="Domain"/>,
 116        /// <see cref="MachineAccountName"/> and <see cref="MachineAccountPassword"/>
 117        /// options. If provided, this connection will be used and the
 118        /// <see cref="Domain"/>, <see cref="MachineAccountName"/> and
 119        /// <see cref="MachineAccountPassword"/>  options will not be used to create
 120        /// the <see cref="LdapConnection"/>.
 121        /// </summary>
 122        internal LdapConnection LdapConnection
 123        {
 124            get
 125            {
 0126                if (_ldapConnection == null)
 0127                    _ldapConnection = ConnectLDAP();
 0128                return _ldapConnection;
 129            }
 130        }
 131
 132        /// <summary>
 133        /// The sliding expiration that should be used for entries in the cache for user claims, defaults to 10 minutes.
 134        /// This is a sliding expiration that will extend each time claims for a user is retrieved.
 135        /// </summary>
 9136        public TimeSpan ClaimsCacheSlidingExpiration { get; set; } = TimeSpan.FromMinutes(10);
 137
 138        /// <summary>
 139        /// The absolute expiration that should be used for entries in the cache for user claims, defaults to 60 minutes
 140        /// This is an absolute expiration that starts when a claims for a user is retrieved for the first time.
 141        /// </summary>
 9142        public TimeSpan ClaimsCacheAbsoluteExpiration { get; set; } = TimeSpan.FromMinutes(60);
 143
 144        /// <summary>
 145        /// The maximum size of the claim results cache, defaults to 100 MB.
 146        /// </summary>
 18147        public int ClaimsCacheSize { get; set; } = 100 * 1024 * 1024;
 148
 9149        internal MemoryCache ClaimsCache { get; set; }
 150
 151        /// <summary>
 152        /// Validates the <see cref="LdapSettings"/>.
 153        /// </summary>
 154        public void Validate()
 155        {
 18156            if (EnableLdapClaimResolution)
 157            {
 9158                if (Servers == null || Servers.Length == 0)
 159                {
 0160                    throw new ArgumentException(SR.Format(SR.EnableLdapClaimResolutionServer, nameof(EnableLdapClaimReso
 161                }
 9162                if (string.IsNullOrEmpty(Domain))
 163                {
 0164                    throw new ArgumentException(SR.Format(SR.EnableLdapClaimResolutionDomain, nameof(EnableLdapClaimReso
 165                }
 166
 9167                if (string.IsNullOrEmpty(MachineAccountName) && !string.IsNullOrEmpty(MachineAccountPassword))
 168                {
 0169                    throw new ArgumentException(SR.Format(SR.EnableLdapClaimResolutionMachine, nameof(MachineAccountPass
 170                }
 171            }
 18172        }
 173
 174        private LdapConnection ConnectLDAP()
 175        {
 0176            if (EnableLdapClaimResolution)
 177            {
 0178                Validate();
 0179                var di = new LdapDirectoryIdentifier(Servers, true, false);
 0180                if (string.IsNullOrEmpty(MachineAccountName))
 181                {
 182                    // Use default credentials
 0183                    _ldapConnection = new LdapConnection(di, null, AuthType.Kerberos);
 184                }
 185                else
 186                {
 187                    // Use specific specific machine account
 0188                    var machineAccount = MachineAccountName + "@" + Domain;
 0189                    var credentials = new NetworkCredential(machineAccount, MachineAccountPassword);
 0190                    _ldapConnection = new LdapConnection(di, credentials);
 191                }
 0192                _ldapConnection.SessionOptions.ProtocolVersion = 3; //Setting LDAP Protocol to latest version
 0193                _ldapConnection.Timeout = TimeSpan.FromMinutes(1);
 194
 0195                _ldapConnection.Bind(); // This line actually makes the connection.
 196            }
 0197            return _ldapConnection;
 198        }
 199    }
 200}