Opsætning af remote login

Oprettet af Robert Holm, Ændret den Mon, 05 Sep 2022 kl. 05:31 AM af Robert Holm

Det følgende beskriver remote login modulets flow. og hvordan det skal sættes op i Bookhus samt
kode eksempler.


Pointen med remote login er at man kan indeslutte Bookhus i virksomhedens medlemsportal.

PÅ den måde kan man sikre at det kun er melemmer i jeres medlemssystem der har adgang til at leje jeres huse.

 

Flow



 

Lejer vises huse på et offentligt domæne.


Lejer finder periode og trykker vælg.



Et billede, der indeholder tekst

Automatisk genereret beskrivelse



Lejer sendes fra Bookhus portalen til jeres Medlemsside login. Her logger medlemmet ind med NemID eller MitID eller anden medlems log-ind metode.




Efter medlemmet er logget ind – sendes medlemmet til en side med en ”Gå til booking” knap.

  1. Knappen på siden i jeres medlemsportal, kodes med Bookhus logininformationer der enten opretter eller opdaterer eksisterende bruger på Bookhus portalen. Kommunikationen indeholder Fornavn, Efternavn og medlemsnummer


Lejer sendes fra medlemsportalen tilbage til Bookhus portalen, nu logget ind, og kan gå videre med bookingen.


URL'en som kunden skal returneres til er

https://{DOMÆNE}/book/{emneID}


Bookhus opsætning


På jeres portal skal der opsættes den URL som brugeren skal omdirigeres til.


eks.

api.mitdomæne.dk/incomminglogin/


Den indskrives i sektionen under "Andre indstillinger" på 
https://{domæne}/admin_web.aspx

Andre flue ben som skal sætte er

  • Gå til denne side i stedet for book
  • Dette gælder kun for gæst
  • Remote login oprette bruger som ikke findes.


 


Kode eksempel


Bookhus har et api endpoint som hedder 

https://{DOMÆNE}/account/remotelogin2


Det tilgås via et GET opkald. 


Endpointet tager imod en krypteret JSON pakke som har elementerne token og data.

Token er den tidsbegrænsede token og data er brugerens medlemsnummer.

 

Krypteringen af datapakken gøres med standard AES.  Selve Token er en 2faktor token, som genereres. 


#Kryptering
public static string EncryptString(string key, string text)
        {
            var iv = new byte[16];
            byte[] array;
            using (var aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                var encrypter = aes.CreateEncryptor(aes.Key, aes.IV);
                using (var ms = new MemoryStream())
                using (var cs = new CryptoStream(ms, encrypter, CryptoStreamMode.Write))
                {
                    using (var sw = new StreamWriter(cs))
                    {
                        sw.Write(text);
                    }
                    array = ms.ToArray();
                }
            }
            return Convert.ToBase64String(array);
        }

        public static string DecryptString(string key, string cipherText)
        {
            var iv = new byte[16];
            byte[] buffer = Convert.FromBase64String(cipherText);

            using (var aes = Aes.Create())
            {
                aes.Key = Encoding.UTF8.GetBytes(key);
                aes.IV = iv;

                var decrypter = aes.CreateDecryptor(aes.Key, aes.IV);

                using (var ms = new MemoryStream(buffer))
                using (var cs = new CryptoStream(ms, decrypter, CryptoStreamMode.Read))
                using (var sr = new StreamReader(cs))
                {
                    return sr.ReadToEnd();
                }
            }
        }


#Token
public static class Twofactor
    {
        private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

        private static string GeneratePincode(string secret, long iterationNumber, int digits = 6)
        {
            var key = Encoding.ASCII.GetBytes(secret);
            return GeneratePincode(key, iterationNumber, digits);
        }

        private static string GeneratePincode(byte[] key, long iterationNumber, int digits = 6)
        {
            var counter = BitConverter.GetBytes(iterationNumber);

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(counter);
            }

            var hmac = new HMACSHA1(key, true);

            var hash = hmac.ComputeHash(counter);

            var offset = hash[hash.Length - 1] & 0xf;

            var binary =
                ((hash[offset] & 0x7f) << 24)
                | ((hash[offset + 1] & 0xff) << 16)
                | ((hash[offset + 2] & 0xff) << 8)
                | (hash[offset + 3] & 0xff);

            var password = binary % (int)Math.Pow(10, digits); // 6 digits

            return password.ToString(new string('0', digits));
        }

        private static long GetCurrentCounter()
        {
            var counter = (long)(DateTime.UtcNow - UnixEpoch).TotalSeconds / 30;
            return counter;
        }

        public static string GetPincode(string secret)
        {
            var counter = GetCurrentCounter();

            return GeneratePincode(secret, counter);
        }

        public static string GetPincode(byte[] secret)
        {
            var counter = GetCurrentCounter();

            return GeneratePincode(secret, counter);
        }

        public static bool IsValid(string secret, string pincode, int checkAdjacentIntervals = 1)
        {
            if (pincode == GetPincode(secret))
            {
                return true;
            }

            for (var i = 1; i <= checkAdjacentIntervals; i++)
            {
                if (pincode == GeneratePincode(secret, GetCurrentCounter() + i))
                {
                    return true;
                }
                if (pincode == GeneratePincode(secret, GetCurrentCounter() - i))
                {
                    return true;
                }
            }
            
            return false;
        }

        public static string GenerateSecret()
        {
            var buffer = new byte[9];

            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(buffer);
            }

            // Generates a 16 character string of A-Z, a-z, 0-9
            // Don't need to worry about any = padding from the
            // Base64 encoding, since our input buffer is divisible by 3
            var secret = Convert.ToBase64String(buffer).Substring(0, 10).Replace('/', '0').Replace('+', '1');
            return secret;
        }
    }


API Variabler


Data der sendes fra jeres Interne portal til Bookhus, krypteres via en API nøgle.
Disse sættes i API modul på jeres portal, og kan findes på siden.

https://{domæne}/Admin/Security/Apikeys


Et billede, der indeholder bord

Automatisk genereret beskrivelse

Projekt:


I toppen indsættes API variabler som hentes fra jeres portal.


public ActionResult Index()
        {
            var cryptoKey = "{NØGLE}$";
            var apiKey = "{HEMMELIG NØGLE}";
            var domain = "{DOMÆNE}.bookhus.dk";
            var medlemsnummer = "{MEDLEMSNUMMER}";

            var token = Twofactor.GetPincode(apiKey);

            var data = new 
            {
                token = token,
                data = medlemsnummer
            };

            var jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(data);

            var encryptedData = AESCrypto.EncryptString(cryptoKey, jsonData);

            var link = string.Format(https://{0}/account/remotelogin2?data={1}, domain, encryptedData);

            ViewBag.Link = link;

            return View();
        }


Var denne artikel nyttig?

Fantastisk!

Tak for din feedback

Beklager, at vi ikke var nyttige

Tak for din feedback

Fortæl os, hvordan vi kan forbedre denne artikel!

Vælg mindst én af grundene

Feedback sendt

Vi sætter pris på din indsats og vil forsøge at rette artiklen