public async Task <ActionResult <BankIdLoginApiInitializeResponse> > InitializeAsync(BankIdLoginApiInitializeRequest request)
        {
            var endUserIp = HttpContext.Connection.RemoteIpAddress.ToString();
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Parse(request.PersonalIdentityNumber);

            AuthResponse authResponse;

            try
            {
                authResponse = await _bankIdApiClient.AuthAsync(endUserIp, personalIdentityNumber.ToLongString());
            }
            catch (BankIdApiException bankIdApiException)
            {
                _logger.BankIdAuthFailure(personalIdentityNumber, bankIdApiException);

                var errorStatusMessage = GetStatusMessage(bankIdApiException);
                return(BadRequest(new BankIdLoginApiErrorResponse(errorStatusMessage)));
            }

            var orderRef          = authResponse.OrderRef;
            var protectedOrderRef = _orderRefProtector.Protect(new BankIdOrderRef()
            {
                OrderRef = orderRef
            });

            _logger.BankIdAuthSuccess(personalIdentityNumber, orderRef);

            return(Ok(new BankIdLoginApiInitializeResponse
            {
                OrderRef = protectedOrderRef
            }));
        }
        public void Month_Equals_Month(int year, int month, int day, int serialNumber, int checksum)
        {
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Create(year, month, day, serialNumber, checksum);
            var dateOfBirth            = personalIdentityNumber.GetDateOfBirthHint();

            Assert.Equal(month, dateOfBirth.Month);
        }
        public void When_Not_Yet_Born_Throws_Exception(int year, int month, int day, int serialNumber, int checksum)
        {
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Create(year, month, day, serialNumber, checksum);
            var ex = Assert.Throws <Exception>(() => personalIdentityNumber.GetAgeHint(_date_2000_04_14));

            Assert.Contains("The person is not yet born.", ex.Message);
        }
예제 #4
0
 internal BankIdAspNetAuthenticateSuccessEvent(AuthenticationTicket authenticationTicket, SwedishPersonalIdentityNumber personalIdentityNumber, BankIdSupportedDevice detectedUserDevice)
     : base(BankIdEventTypes.AspNetAuthenticateSuccessEventId, BankIdEventTypes.AspNetAuthenticateSuccessEventName, BankIdEventSeverity.Success)
 {
     AuthenticationTicket = authenticationTicket;
     PersonalIdentityNumber = personalIdentityNumber;
     DetectedUserDevice = detectedUserDevice;
 }
예제 #5
0
        public void TryParse_Returns_False_And_Outputs_Null_When_Invalid_Day()
        {
            var isValid = SwedishPersonalIdentityNumber.TryParse("170199-2388", out SwedishPersonalIdentityNumber personalIdentityNumber);

            Assert.False(isValid);
            Assert.Null(personalIdentityNumber);
        }
        private void AddOptionalClaims(List <Claim> claims, SwedishPersonalIdentityNumber personalIdentityNumber, DateTimeOffset?expiresUtc)
        {
            if (expiresUtc.HasValue)
            {
                claims.Add(new Claim(BankIdClaimTypes.Expires, JwtSerializer.GetExpires(expiresUtc.Value)));
            }

            if (Options.IssueAuthenticationMethodClaim)
            {
                claims.Add(new Claim(BankIdClaimTypes.AuthenticationMethod, Options.AuthenticationMethodName));
            }

            if (Options.IssueIdentityProviderClaim)
            {
                claims.Add(new Claim(BankIdClaimTypes.IdentityProvider, Options.IdentityProviderName));
            }

            if (Options.IssueGenderClaim)
            {
                var jwtGender = JwtSerializer.GetGender(personalIdentityNumber.GetGenderHint());
                if (!string.IsNullOrEmpty(jwtGender))
                {
                    claims.Add(new Claim(BankIdClaimTypes.Gender, jwtGender));
                }
            }

            if (Options.IssueBirthdateClaim)
            {
                var jwtBirthdate = JwtSerializer.GetBirthdate(personalIdentityNumber.GetDateOfBirthHint());
                claims.Add(new Claim(BankIdClaimTypes.Birthdate, jwtBirthdate));
            }
        }
예제 #7
0
        public void TryParse_Returns_True_And_Outs_PIN_When_Valid_PIN()
        {
            var isValid = SwedishPersonalIdentityNumber.TryParse("000101-2384", out SwedishPersonalIdentityNumber personalIdentityNumber);

            Assert.True(isValid);
            Assert.Equal(SwedishPersonalIdentityNumber.Create(2000, 01, 01, 238, 4), personalIdentityNumber);
        }
        public void A_PIN_Is_Not_Equal_Object_Null_Using_Method()
        {
            var personalIdentityNumber1 = SwedishPersonalIdentityNumber.Parse("199908072391");
            var equals = personalIdentityNumber1.Equals((object)null);

            Assert.False(equals);
        }
        protected override IEnumerable <Claim> GetClaims(BankIdGetSessionResponse loginResult)
        {
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Parse(loginResult.UserAttributes.PersonalIdentityNumber);
            var claims = new List <Claim>
            {
                new Claim(GrandIdClaimTypes.Subject, personalIdentityNumber.To12DigitString()),

                new Claim(GrandIdClaimTypes.Name, loginResult.UserAttributes.Name),
                new Claim(GrandIdClaimTypes.FamilyName, loginResult.UserAttributes.Surname),
                new Claim(GrandIdClaimTypes.GivenName, loginResult.UserAttributes.GivenName),

                new Claim(GrandIdClaimTypes.SwedishPersonalIdentityNumber, personalIdentityNumber.To10DigitString())
            };

            if (Options.IssueGenderClaim)
            {
                var jwtGender = JwtSerializer.GetGender(personalIdentityNumber.GetGenderHint());
                if (!string.IsNullOrEmpty(jwtGender))
                {
                    claims.Add(new Claim(GrandIdClaimTypes.Gender, jwtGender));
                }
            }

            if (Options.IssueBirthdateClaim)
            {
                var jwtBirthdate = JwtSerializer.GetBirthdate(personalIdentityNumber.GetDateOfBirthHint());
                claims.Add(new Claim(GrandIdClaimTypes.Birthdate, jwtBirthdate));
            }

            return(claims);
        }
예제 #10
0
        public void TryParseInSpecificYear_Returns_True_And_Outs_PIN_When_Valid_PIN()
        {
            var isValid = SwedishPersonalIdentityNumber.TryParseInSpecificYear("990913+9801", 2018, out SwedishPersonalIdentityNumber personalIdentityNumber);

            Assert.True(isValid);
            Assert.Equal(SwedishPersonalIdentityNumber.Create(1899, 09, 13, 980, 1), personalIdentityNumber);
        }
예제 #11
0
        public override Task HandleCollectCompletedEvent(BankIdCollectCompletedEvent e)
        {
            var properties = new Dictionary <string, string>
            {
                { PropertyName_BankIdOrderRef, e.OrderRef }
            };

            if (_options.LogUserNames)
            {
                properties.Add(PropertyName_UserName, e.CompletionData.User.Name);
                properties.Add(PropertyName_UserGivenName, e.CompletionData.User.GivenName);
                properties.Add(PropertyName_UserSurname, e.CompletionData.User.Surname);
            }

            if (_options.LogDeviceIpAddress)
            {
                properties.Add(PropertyName_BankIdUserDeviceIpAddress, e.CompletionData.Device.IpAddress);
            }

            if (_options.LogCertificateDates)
            {
                properties.Add(PropertyName_BankIdUserCertNotBefore, e.CompletionData.Cert.NotBefore);
                properties.Add(PropertyName_BankIdUserCertNotAfter, e.CompletionData.Cert.NotAfter);
            }

            var swedishPersonalIdentityNumber = SwedishPersonalIdentityNumber.Parse(e.CompletionData.User.PersonalIdentityNumber);

            return(Track(
                       e,
                       properties,
                       personalIdentityNumber: swedishPersonalIdentityNumber
                       ));
        }
        private void AddOptionalClaims(List <Claim> claims, SwedishPersonalIdentityNumber personalIdentityNumber, DateTimeOffset?expiresUtc)
        {
            if (expiresUtc.HasValue)
            {
                claims.Add(new Claim(BankIdClaimTypes.Expires, expiresUtc.Value.ToUnixTimeSeconds().ToString("D")));
            }

            if (Options.IssueAuthenticationMethodClaim)
            {
                claims.Add(new Claim(BankIdClaimTypes.AuthenticationMethod, Options.AuthenticationMethodName));
            }

            if (Options.IssueIdentityProviderClaim)
            {
                claims.Add(new Claim(BankIdClaimTypes.IdentityProvider, Options.IdentityProviderName));
            }

            if (Options.IssueGenderClaim)
            {
                // Specified in: http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.1
                var jwtGender = GetJwtGender(personalIdentityNumber.Gender);
                if (!string.IsNullOrEmpty(jwtGender))
                {
                    claims.Add(new Claim(BankIdClaimTypes.Gender, jwtGender));
                }
            }

            if (Options.IssueBirthdateClaim)
            {
                // Specified in: http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.1
                var jwtBirthdate = GetJwtBirthdate(personalIdentityNumber.DateOfBirth);
                claims.Add(new Claim(BankIdClaimTypes.Birthdate, jwtBirthdate));
            }
        }
예제 #13
0
        protected override Task <HandleRequestResult> HandleRemoteAuthenticateAsync()
        {
            var state = GetStateFromCookie();

            if (state == null)
            {
                return(HandleRemoteAuthenticateFail("Invalid state cookie"));
            }

            DeleteStateCookie();

            var loginResultProtected = Request.Query["loginResult"];

            if (string.IsNullOrEmpty(loginResultProtected))
            {
                return(HandleRemoteAuthenticateFail("Missing login result"));
            }

            var loginResult = _loginResultProtector.Unprotect(loginResultProtected);

            if (loginResult == null || !loginResult.IsSuccessful)
            {
                return(HandleRemoteAuthenticateFail("Invalid login result"));
            }

            var properties = state.AuthenticationProperties;
            var ticket     = GetAuthenticationTicket(loginResult, properties);

            _bankIdEventTrigger.TriggerAsync(new BankIdAspNetAuthenticateSuccessEvent(
                                                 ticket,
                                                 SwedishPersonalIdentityNumber.Parse(loginResult.PersonalIdentityNumber)
                                                 ));

            return(Task.FromResult(HandleRequestResult.Success(ticket)));
        }
예제 #14
0
        public void Day_Equals_Day(int year, int month, int day, int birthNumber, int checksum)
        {
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Create(year, month, day, birthNumber, checksum);
            var dateOfBirth            = personalIdentityNumber.GetDateOfBirthHint();

            Assert.Equal(day, dateOfBirth.Day);
        }
        public void Two_Different_PIN_Are_Not_Equal_Using_Method()
        {
            var personalIdentityNumber1 = SwedishPersonalIdentityNumber.Parse("199908072391");
            var personalIdentityNumber2 = SwedishPersonalIdentityNumber.Parse("191202119986");
            var equals = personalIdentityNumber1.Equals(personalIdentityNumber2);

            Assert.False(equals);
        }
        public void Two_Different_PIN_Are_Not_Equal_Using_Operator()
        {
            var personalIdentityNumber1 = SwedishPersonalIdentityNumber.Parse("199908072391");
            var personalIdentityNumber2 = SwedishPersonalIdentityNumber.Parse("191202119986");
            var equals = personalIdentityNumber1 != personalIdentityNumber2;

            Assert.True(equals);
        }
예제 #17
0
 public BankIdLoginOptions(List <string> certificatePolicies, SwedishPersonalIdentityNumber personalIdentityNumber, bool allowChangingPersonalIdentityNumber, bool autoLaunch, bool allowBiometric)
 {
     CertificatePolicies    = certificatePolicies;
     PersonalIdentityNumber = personalIdentityNumber;
     AllowChangingPersonalIdentityNumber = allowChangingPersonalIdentityNumber;
     AutoLaunch     = autoLaunch;
     AllowBiometric = allowBiometric;
 }
예제 #18
0
        public void Two_Identical_PIN_Returns_Same_Hashcode()
        {
            var personalIdentityNumberString = "199908072391";
            var personalIdentityNumber1      = SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);
            var personalIdentityNumber2      = SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);

            Assert.Equal(personalIdentityNumber1.GetHashCode(), personalIdentityNumber2.GetHashCode());
        }
        public void Two_Identical_PIN_When_One_Is_Object_Are_Equal_Using_Method()
        {
            var personalIdentityNumberString = "199908072391";
            var personalIdentityNumber1      = SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);
            var personalIdentityNumber2      = (object)SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);
            var equals = personalIdentityNumber1.Equals(personalIdentityNumber2);

            Assert.True(equals);
        }
        public void Two_Identical_PIN_Are_Equal_Using_Operator()
        {
            var personalIdentityNumberString = "199908072391";
            var personalIdentityNumber1      = SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);
            var personalIdentityNumber2      = SwedishPersonalIdentityNumber.Parse(personalIdentityNumberString);
            var equals = personalIdentityNumber1 == personalIdentityNumber2;

            Assert.True(equals);
        }
        private static int?TryGetAgeHint(SwedishPersonalIdentityNumber pin, DateTime dateOfBirthHint)
        {
            if (dateOfBirthHint > DateTime.UtcNow.Date)
            {
                return(null);
            }

            return(pin.GetAgeHint());
        }
예제 #22
0
        public void Accepts_Valid_Personal_Identity_Number(int year, int month, int day, int birthNumber, int checksum)
        {
            var personalIdentityNumber = SwedishPersonalIdentityNumber.Create(year, month, day, birthNumber, checksum);

            Assert.Equal(year, personalIdentityNumber.Year);
            Assert.Equal(month, personalIdentityNumber.Month);
            Assert.Equal(day, personalIdentityNumber.Day);
            Assert.Equal(birthNumber, personalIdentityNumber.BirthNumber);
            Assert.Equal(checksum, personalIdentityNumber.Checksum);
        }
예제 #23
0
        public async Task <ActionResult <BankIdLoginApiInitializeResponse> > InitializeAsync(BankIdLoginApiInitializeRequest request)
        {
            var unprotectedLoginOptions = _loginOptionsProtector.Unprotect(request.LoginOptions);

            SwedishPersonalIdentityNumber personalIdentityNumber;

            if (unprotectedLoginOptions.IsAutoLogin())
            {
                personalIdentityNumber = unprotectedLoginOptions.PersonalIdentityNumber;
            }
            else
            {
                if (!SwedishPersonalIdentityNumber.TryParse(request.PersonalIdentityNumber, out personalIdentityNumber))
                {
                    return(BadRequest(new
                    {
                        PersonalIdentityNumber = "Invalid PersonalIdentityNumber."
                    }));
                }
            }

            AuthResponse authResponse;

            try
            {
                var authRequest = GetAuthRequest(personalIdentityNumber, unprotectedLoginOptions);
                authResponse = await _bankIdApiClient.AuthAsync(authRequest);
            }
            catch (BankIdApiException bankIdApiException)
            {
                _logger.BankIdAuthFailure(personalIdentityNumber, bankIdApiException);

                var errorStatusMessage = GetStatusMessage(bankIdApiException);
                return(BadRequest(new BankIdLoginApiErrorResponse(errorStatusMessage)));
            }

            var orderRef          = authResponse.OrderRef;
            var protectedOrderRef = _orderRefProtector.Protect(new BankIdOrderRef(orderRef));

            _logger.BankIdAuthSuccess(personalIdentityNumber, orderRef);

            if (unprotectedLoginOptions.AutoLaunch)
            {
                var detectedDevice    = _bankIdSupportedDeviceDetector.Detect(HttpContext.Request.Headers["User-Agent"]);
                var bankIdRedirectUri = GetBankIdRedirectUri(request, protectedOrderRef, authResponse, detectedDevice);

                var response = detectedDevice.IsIos
                    ? BankIdLoginApiInitializeResponse.AutoLaunch(protectedOrderRef, bankIdRedirectUri, false)
                    : BankIdLoginApiInitializeResponse.AutoLaunchAndCheckStatus(protectedOrderRef, bankIdRedirectUri, detectedDevice.IsAndroid);

                return(Ok(response));
            }

            return(Ok(BankIdLoginApiInitializeResponse.ManualLaunch(protectedOrderRef)));
        }
예제 #24
0
        private AuthRequest GetAuthRequest(SwedishPersonalIdentityNumber personalIdentityNumber, BankIdLoginOptions loginOptions)
        {
            var endUserIp                    = GetEndUserIp();
            var certificatePolicies          = loginOptions.CertificatePolicies?.Any() ?? false ? loginOptions.CertificatePolicies : null;
            var personalIdentityNumberString = personalIdentityNumber?.To12DigitString();
            var autoStartTokenRequired       = string.IsNullOrEmpty(personalIdentityNumberString) ? true : (bool?)null;

            var authRequestRequirement = new Requirement(certificatePolicies, autoStartTokenRequired, loginOptions.AllowBiometric);

            return(new AuthRequest(endUserIp, personalIdentityNumberString, authRequestRequirement));
        }
예제 #25
0
 private static void WritePersonalIdentityNumberInfo(string rawPersonalIdentityNumber)
 {
     WriteHeader($"Input: {rawPersonalIdentityNumber}");
     if (SwedishPersonalIdentityNumber.TryParse(rawPersonalIdentityNumber, out var personalIdentityNumber))
     {
         WritePersonalIdentityNumberInfo(personalIdentityNumber);
     }
     else
     {
         Console.Error.WriteLine("Unable to parse the input as a SwedishPersonalIdentityNumber.");
     }
 }
예제 #26
0
        private static SwedishPersonalIdentityNumber GetSwedishPersonalIdentityNumber(AuthenticationProperties properties)
        {
            if (properties.Items.TryGetValue(BankIdAuthenticationConstants.AuthenticationPropertyItemSwedishPersonalIdentityNumber, out var swedishPersonalIdentityNumber))
            {
                if (!string.IsNullOrWhiteSpace(swedishPersonalIdentityNumber))
                {
                    return(SwedishPersonalIdentityNumber.Parse(swedishPersonalIdentityNumber));
                }
            }

            return(null);
        }
        /// <summary>Validates the specified Swedish Personal Identity Number with respect to the current validation attribute.</summary>
        /// <param name="value">The Swedish Personal Identity Number to validate.</param>
        /// <param name="validationContext">The context information about the validation operation.</param>
        /// <returns>An instance of the <see cref="System.ComponentModel.DataAnnotations.ValidationResult"></see> class.</returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var valueString = (string)value;

            if (!SwedishPersonalIdentityNumber.TryParse(valueString, out _))
            {
                var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                return(new ValidationResult(errorMessage));
            }

            return(ValidationResult.Success);
        }
        public void GetAgeHint_Handles_LeapYears_Correctly(string personalIdentityNumber, string actualDate, int expectedAge)
        {
            // Arrange
            var swedishPersonalIdentityNumber = SwedishPersonalIdentityNumber.Parse(personalIdentityNumber);
            var date = DateTime.ParseExact(actualDate, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);

            // Act
            var age = swedishPersonalIdentityNumber.GetAgeHint(date);

            // Assert
            Assert.Equal(expectedAge, age);
        }
        private SwedishPersonalIdentityNumber GetSwedishPersonalIdentityNumber(AuthenticationProperties properties)
        {
            bool TryGetPinString(out string s)
            {
                return(properties.Items.TryGetValue(GrandIdAuthenticationConstants.AuthenticationPropertyItemSwedishPersonalIdentityNumber, out s));
            }

            if (TryGetPinString(out var swedishPersonalIdentityNumber) && !string.IsNullOrWhiteSpace(swedishPersonalIdentityNumber))
            {
                return(SwedishPersonalIdentityNumber.Parse(swedishPersonalIdentityNumber));
            }

            return(null);
        }
예제 #30
0
 protected override ValidationResult IsValid(object value, ValidationContext validationContext)
 {
     if (SwedishPersonalIdentityNumber.TryParse((string)value, out var personalIdentityNumber))
     {
         if (personalIdentityNumber.GetAge() >= 18)
         {
             return(ValidationResult.Success);
         }
         else
         {
             return(new ValidationResult("Du måste vara minst 18 år gammal."));
         }
     }
     return(new ValidationResult("Ogiltigt personnummer."));
 }