Context object used to control flow of basic authentication.
상속: BaseBasicContext
예제 #1
0
        private ClaimsPrincipal SignInUsingSecret(BasicSignInContext context) {
            if (_options.Secret != context.Password) {
                return null;
            }

            var claims = new[] {
                new Claim(ClaimTypes.Name, context.Username),
                new Claim(Claims.RUser, "")
            };

            var identity = new ClaimsIdentity(claims, context.Options.AuthenticationScheme);
            return new ClaimsPrincipal(identity);
        }
예제 #2
0
        public async Task SignInAsync(BasicSignInContext context) {
            ClaimsPrincipal principal;
            if (context.IsSignInRequired()) {
                principal = (_options.Secret != null) ? SignInUsingSecret(context) : await SignInUsingLogonAsync(context);
            } else {
                var claims = new[] { new Claim(ClaimTypes.Anonymous, "") };
                var claimsIdentity = new ClaimsIdentity(claims, context.Options.AuthenticationScheme);
                principal = new ClaimsPrincipal(claimsIdentity);
            }

            if (principal != null) {
                context.Ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), context.Options.AuthenticationScheme);
            }

            context.HandleResponse();
        }
예제 #3
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var events = Events as BasicEvents;

            try {
                // .NET Core as of 2.0 does not support HTTP auth on sockets
                // This is alternative solution to anonymous access in SessionController.GetPipe()
                // but it only works for local connections (which may be OK for VSC but it won't work
                // in VSC with remote or Docker containers.

                //if (Uri.TryCreate(CurrentUri, UriKind.Absolute, out var uri)) {
                //    if (uri.IsLoopback && !Request.IsHttps) {
                //        var claims = new[] {
                //            new Claim(ClaimTypes.Name, "RTVS"),
                //            new Claim(Claims.RUser, string.Empty),
                //        };
                //        var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, BasicDefaults.AuthenticationScheme));
                //        var t = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name);
                //        return AuthenticateResult.Success(t);
                //    }
                //}

                // retrieve authorization header
                string authorization = Request.Headers[HeaderNames.Authorization];

                if (string.IsNullOrEmpty(authorization))
                {
                    return(AuthenticateResult.NoResult());
                }

                if (!authorization.StartsWith(RequestHeaderPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    return(AuthenticateResult.NoResult());
                }

                // retrieve credentials from header
                var encodedCredentials = authorization.Substring(RequestHeaderPrefix.Length);
                var decodedCredentials = default(string);
                try {
                    decodedCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(encodedCredentials));
                } catch (Exception) {
                    return(AuthenticateResult.Fail("Invalid basic authentication header encoding."));
                }

                var index = decodedCredentials.IndexOf(':');
                if (index == -1)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication header format."));
                }

                var username      = decodedCredentials.Substring(0, index);
                var password      = decodedCredentials.Substring(index + 1);
                var signInContext = new BasicSignInContext(Context, Scheme, Options)
                {
                    Username = username,
                    Password = password,
                };

                await events.SignIn(signInContext);

                if (signInContext.Principal == null)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication credentials."));
                }

                var ticket = new AuthenticationTicket(signInContext.Principal, new AuthenticationProperties(), Scheme.Name);

                return(AuthenticateResult.Success(ticket));
            } catch (Exception ex) {
                var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                {
                    Exception = ex,
                };

                await events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.Result != null)
                {
                    return(authenticationFailedContext.Result);
                }

                throw;
            }
        }
예제 #4
0
 /// <summary>
 /// Implements the interface method by invoking the related delegate method
 /// </summary>
 /// <param name="context"></param>
 public virtual Task SignIn(BasicSignInContext context) => OnSignIn(context);
예제 #5
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            try
            {
                // retrieve authorization header
                string authorization = Request.Headers[HeaderNames.Authorization];

                if (string.IsNullOrEmpty(authorization))
                {
                    return(AuthenticateResult.NoResult());
                }

                if (!authorization.StartsWith(RequestHeaderPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    return(AuthenticateResult.NoResult());
                }

                // retrieve credentials from header
                var encodedCredentials = authorization.Substring(RequestHeaderPrefix.Length);
                var decodedCredentials = default(string);
                try
                {
                    decodedCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(encodedCredentials));
                }
                catch (Exception)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication header encoding."));
                }

                var index = decodedCredentials.IndexOf(':');
                if (index == -1)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication header format."));
                }

                var username = decodedCredentials.Substring(0, index);
                var password = decodedCredentials.Substring(index + 1);

                // invoke sign in event
                var signInContext = new BasicSignInContext(Context, Scheme, Options)
                {
                    Username = username,
                    Password = password,
                };
                await Events.SignIn(signInContext);

                if (signInContext.Result != null)
                {
                    return(signInContext.Result);
                }

                // allow sign in event to modify received credentials
                username = signInContext.Username;
                password = signInContext.Password;

                // verify credentials against options
                BasicCredential credentials = null;
                for (var i = 0; i < Options.Credentials.Length; i++)
                {
                    var currentCredentials = Options.Credentials[i];

                    if (currentCredentials.Username == username && currentCredentials.Password == password)
                    {
                        credentials = currentCredentials;
                        break;
                    }
                }
                if (credentials == null)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication credentials."));
                }

                var claims = new Claim[credentials.Claims.Length + 1];
                claims[0] = new Claim(ClaimsIdentity.DefaultNameClaimType, credentials.Username);
                for (var i = 0; i < credentials.Claims.Length; i++)
                {
                    var currentClaim = credentials.Claims[i];

                    claims[i + 1] = new Claim(currentClaim.Type, currentClaim.Value);
                }

                var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));

                var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name);

                return(AuthenticateResult.Success(ticket));
            }
            catch (Exception ex)
            {
                var authenticationFailedContext = new AuthenticationFailedContext(Context, Scheme, Options)
                {
                    Exception = ex,
                };

                await Events.AuthenticationFailed(authenticationFailedContext);

                if (authenticationFailedContext.Result != null)
                {
                    return(authenticationFailedContext.Result);
                }

                throw;
            }
        }
예제 #6
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            try
            {
                var feat = Context.Features.OfType <HttpRequestFeature>();

                var headers = Request.Headers[RequestHeader];
                if (headers.Count <= 0)
                {
                    return(AuthenticateResult.Fail("No authorization header."));
                }

                var header = headers.Where(h => h.StartsWith(RequestHeaderPrefix, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                if (header == null)
                {
                    return(AuthenticateResult.Fail("Not basic authentication header."));
                }

                var encoded = header.Substring(RequestHeaderPrefix.Length);
                var decoded = default(string);
                try
                {
                    decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded));
                }
                catch (Exception)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication header encoding."));
                }

                var index = decoded.IndexOf(':');
                if (index == -1)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication header format."));
                }

                var username = decoded.Substring(0, index);
                var password = decoded.Substring(index + 1);

                var signInContext = new BasicSignInContext(Context, Options, username, password);
                await Options.Events.SignIn(signInContext);

                if (signInContext.HandledResponse)
                {
                    if (signInContext.Ticket != null)
                    {
                        return(AuthenticateResult.Success(signInContext.Ticket));
                    }
                    else
                    {
                        return(AuthenticateResult.Fail("Invalid basic authentication credentials."));
                    }
                }

                if (signInContext.Skipped)
                {
                    return(AuthenticateResult.Success(null));
                }

                var credentials = Options.Credentials.Where(c => c.Username == username && c.Password == password).FirstOrDefault();
                if (credentials == null)
                {
                    return(AuthenticateResult.Fail("Invalid basic authentication credentials."));
                }

                var claims = credentials.Claims.Select(c => new Claim(c.Type, c.Value)).ToList();
                if (!claims.Any(c => c.Type == ClaimTypes.Name))
                {
                    claims.Add(new Claim(ClaimTypes.Name, username));
                }

                var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Options.AuthenticationScheme));

                var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Options.AuthenticationScheme);

                return(AuthenticateResult.Success(ticket));
            }
            catch (Exception ex)
            {
                var exceptionContext = new BasicExceptionContext(Context, Options, ex);

                await Options.Events.Exception(exceptionContext);

                if (exceptionContext.HandledResponse)
                {
                    return(AuthenticateResult.Success(exceptionContext.Ticket));
                }

                if (exceptionContext.Skipped)
                {
                    return(AuthenticateResult.Success(null));
                }

                throw;
            }
        }
예제 #7
0
        private async Task<ClaimsPrincipal> SignInUsingLogonAsync(BasicSignInContext context) {
            var user = new StringBuilder(NativeMethods.CREDUI_MAX_USERNAME_LENGTH + 1);
            var domain = new StringBuilder(NativeMethods.CREDUI_MAX_PASSWORD_LENGTH + 1);

            uint error = NativeMethods.CredUIParseUserName(context.Username, user, user.Capacity, domain, domain.Capacity);
            if (error != 0) {
                _logger.LogError(Resources.Error_UserNameParse, context.Username, error.ToString("X"));
                return null;
            }

            IntPtr token;
            WindowsIdentity winIdentity = null;

            string profilePath = string.Empty;
            _logger.LogTrace(Resources.Trace_LogOnUserBegin, context.Username);
            if (NativeMethods.LogonUser(user.ToString(), domain.ToString(), context.Password, (int)LogonType.LOGON32_LOGON_NETWORK, (int)LogonProvider.LOGON32_PROVIDER_DEFAULT, out token)) {
                _logger.LogTrace(Resources.Trace_LogOnSuccess, context.Username);
                winIdentity = new WindowsIdentity(token);

                StringBuilder profileDir = new StringBuilder(NativeMethods.MAX_PATH * 2);
                uint size = (uint)profileDir.Capacity;
                if (NativeMethods.GetUserProfileDirectory(token, profileDir, ref size)) {
                    profilePath = profileDir.ToString();
                    _logger.LogTrace(Resources.Trace_UserProfileDirectory, context.Username, profilePath);
                } else {
#if DEBUG
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromMinutes(10));
#else
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
#endif
                    _logger.LogTrace(Resources.Trace_UserProfileCreation, context.Username);

                    var result = await _userProfileManager.CreateProfileAsync(new RUserProfileServiceRequest(user.ToString(), domain.ToString(), context.Password.ToSecureString()), cts.Token);
                    if (result.IsInvalidResponse()) {
                        _logger.LogError(Resources.Error_ProfileCreationFailedInvalidResponse, context.Username, Resources.Info_UserProfileServiceName);
                        return null;
                    }

                    error = result.Error;
                    // 0x800700b7 - Profile already exists.
                    if (error != 0 && error != 0x800700b7) {
                        _logger.LogError(Resources.Error_ProfileCreationFailed, context.Username, error.ToString("X"));
                        return null;
                    } else if (error == 0x800700b7 || result.ProfileExists) {
                        _logger.LogInformation(Resources.Info_ProfileAlreadyExists, context.Username);
                    } else {
                        _logger.LogInformation(Resources.Info_ProfileCreated, context.Username);
                    }

                    if (!string.IsNullOrEmpty(result.ProfilePath)) {
                        profilePath = result.ProfilePath;
                        _logger.LogTrace(Resources.Trace_UserProfileDirectory, context.Username, profilePath);
                    } else {
                        _logger.LogError(Resources.Error_GetUserProfileDirectory, context.Username, Marshal.GetLastWin32Error().ToString("X"));
                    }
                }
            } else {
                _logger.LogError(Resources.Error_LogOnFailed, context.Username, Marshal.GetLastWin32Error().ToString("X"));
                return null;
            }

            var principal = new WindowsPrincipal(winIdentity);
            if (principal.IsInRole(_options.AllowedGroup)) {
                var claims = new[] {
                    //new Claim(ClaimTypes.Name, context.Username),
                    new Claim(Claims.RUser, ""),
                    // TODO: figure out how to avoid keeping raw credentials around. 
                    new Claim(Claims.Password, context.Password),
                    new Claim(Claims.RUserProfileDir, profilePath)
                };

                var claimsIdentity = new ClaimsIdentity(claims, context.Options.AuthenticationScheme);
                principal.AddIdentities(new[] { claimsIdentity });
            }

            return principal;
        }
예제 #8
0
 /// <summary>
 /// Implements the interface method by invoking the related delegate method
 /// </summary>
 /// <param name="context"></param>
 public virtual Task SignIn(BasicSignInContext context) => OnSignIn(context);