Implementasi teknologi SSO berdasarkan Node.js

Aplikasi web dibuat menggunakan arsitektur klien-server menggunakan HTTP sebagai protokol komunikasinya. HTTP adalah protokol tanpa negara. Setiap kali browser mengirim permintaan ke server, server memproses permintaan itu secara independen dari permintaan lain dan tidak mengaitkannya dengan permintaan sebelumnya atau berikutnya dari browser yang sama. Artinya, antara lain, siapa pun dapat mengakses sumber daya server yang tidak dilindungi dengan cara apa pun. Jika Anda perlu melindungi beberapa sumber daya server dari pihak luar, ini berarti Anda harus membatasi apa yang dapat diminta browser dari server. Artinya, Anda perlu mengautentikasi permintaan dan hanya menanggapi yang lulus tes, mengabaikan yang tidak lulus tes. Untuk mengautentikasi permintaan, Anda perlu memiliki beberapa informasi tentang permintaan tersebut,disimpan di sisi browser. Karena protokol HTTP tidak menyimpan status permintaan, kami memerlukan beberapa mekanisme tambahan untuk ini yang memungkinkan server dan browser untuk bersama-sama mengelola status koneksi. Mekanisme ini termasuk penggunaan cookie, sesi, JWT.







Jika kita berbicara tentang proyek web tunggal, maka informasi tentang status sesi interaksi tertentu antara klien dan server mudah dipertahankan menggunakan otentikasi pengguna pada loginnya. Tetapi jika sistem independen semacam itu berevolusi, berubah menjadi beberapa sistem, pengembang dihadapkan pada pertanyaan untuk memelihara informasi tentang status masing-masing sistem yang terpisah ini. Dalam praktiknya, pertanyaan ini terlihat seperti ini: "Apakah pengguna sistem ini harus memasukkan masing-masing secara terpisah dan juga keluar darinya?"



Ada satu aturan praktis tentang sistem yang tumbuh dalam kompleksitas dari waktu ke waktu dan bagaimana sistem tersebut berinteraksi dengan penggunanya. Yakni, beban pemecahan masalah yang terkait dengan komplikasi arsitektur proyek berada pada sistem, dan bukan pada penggunanya. Tidak peduli seberapa kompleks mekanisme internal proyek web. Ini harus terlihat seperti sistem terpadu bagi pengguna. Dengan kata lain, seorang pengguna yang bekerja dengan sistem web yang terdiri dari banyak komponen harus memahami apa yang terjadi seolah-olah ia bekerja dengan satu sistem. Secara khusus, kita berbicara tentang otentikasi dalam sistem seperti itu menggunakan SSO (Sistem Masuk Tunggal) - teknologi sistem masuk tunggal.



Bagaimana cara membuat sistem yang menggunakan SSO? Anda mungkin memikirkan solusi lama berbasis cookie yang bagus di sini, tetapi solusi ini memiliki batasan. Pembatasan berlaku untuk domain tempat cookie dipasang. Ini dapat dielakkan hanya dengan mengumpulkan semua nama domain dari semua subsistem aplikasi web pada satu domain level teratas.



Dalam lingkungan saat ini, solusi tersebut terhalang oleh adopsi arsitektur layanan mikro yang meluas. Manajemen sesi menjadi lebih rumit pada saat teknologi yang berbeda digunakan dalam mengembangkan proyek web, dan ketika layanan yang berbeda terkadang dihosting di domain yang berbeda. Selain itu, layanan web yang dulunya ditulis di Java mulai menulis menggunakan kapabilitas platform Node.js. Ini membuat lebih sulit untuk bekerja dengan cookie. Ternyata sesi sekarang tidak begitu mudah untuk dikelola.



Kesulitan ini telah menyebabkan pengembangan metode baru untuk masuk ke sistem, khususnya, kita berbicara tentang teknologi sistem masuk tunggal.



Teknologi sistem masuk tunggal



Prinsip dasar yang mendasari teknologi sistem masuk tunggal adalah bahwa pengguna dapat masuk ke satu sistem proyek yang terdiri dari banyak sistem dan diotorisasi di semua sistem lain tanpa harus masuk lagi. Pada saat yang sama, kita berbicara tentang jalan keluar terpusat dari semua sistem.



Kami, untuk tujuan pendidikan, akan menerapkan teknologi SSO pada platform Node.js.



Perlu dicatat bahwa penerapan teknologi ini pada skala perusahaan akan membutuhkan lebih banyak upaya daripada yang akan kami lakukan untuk pengembangan sistem pelatihan kami. Itulah mengapa ada solusi SSO khusus yang dirancang untuk proyek skala besar.



Bagaimana login SSO diatur?



Inti dari penerapan SSO adalah satu server otentikasi independen yang dapat menerima informasi untuk mengotentikasi pengguna. Misalnya - alamat email, nama pengguna, kata sandi. Sistem lain tidak menyediakan mekanisme langsung kepada pengguna untuk masuk ke dalamnya. Mereka memberi otorisasi kepada pengguna secara tidak langsung dengan menerima informasi tentang dirinya dari server otentikasi. Mekanisme otorisasi tidak langsung diimplementasikan menggunakan token.



Berikut adalah repositori kode untuk proyek simple-sso, yang implementasinya akan saya jelaskan di sini. Saya menggunakan kerangka kerja Node.js, tetapi Anda dapat menerapkan hal yang sama menggunakan sesuatu yang berbeda. Mari kita ambil analisis langkah demi langkah dari tindakan pengguna yang bekerja dengan sistem, dan mekanisme yang membentuk sistem ini.



Langkah 1



Pengguna mencoba mengakses sumber daya yang dilindungi pada sistem (sebut saja sumber daya ini "konsumen SSO", "konsumen sso"). Konsumen SSO mengetahui bahwa pengguna tidak masuk dan mengarahkan pengguna ke "server SSO" ("sso-server") menggunakan alamatnya sendiri sebagai parameter kueri. Pengguna yang berhasil diautentikasi akan diarahkan ke alamat ini. Mekanisme ini disediakan oleh middleware Express:



const isAuthenticated = (req, res, next) => {
  //   ,   ,
  //     -     SSO-     
  //    URL  URL,     
  // ,   
  const redirectURL = `${req.protocol}://${req.headers.host}${req.path}`;
  if (req.session.user == null) {
    return res.redirect(
      `http://sso.ankuranand.com:3010/simplesso/login?serviceURL=${redirectURL}`
    );
  }
  next();
};

module.exports = isAuthenticated;


Langkah 2



Server SSO mengetahui bahwa pengguna tidak masuk dan mengarahkannya ke halaman masuk:



const login = (req, res, next) => {
  //  req.query  url,      
  //    ,     sso-.
  //        
  //     
  const { serviceURL } = req.query;
  //         URL.
  if (serviceURL != null) {
    const url = new URL(serviceURL);
    if (alloweOrigin[url.origin] !== true) {
      return res
        .status(400)
        .json({ message: "Your are not allowed to access the sso-server" });
    }
  }
  if (req.session.user != null && serviceURL == null) {
    return res.redirect("/");
  }
  //          -  
  //   
  if (req.session.user != null && serviceURL != null) {
    const url = new URL(serviceURL);
    const intrmid = encodedId();
    storeApplicationInCache(url.origin, req.session.user, intrmid);
    return res.redirect(`${serviceURL}?ssoToken=${intrmid}`);
  }

  return res.render("login", {
    title: "SSO-Server | Login"
  });
};


Saya akan membuat beberapa komentar di sini tentang keamanan.



Kami memeriksa serviceURL, datang dalam bentuk parameter permintaan ke server SSO. Ini memungkinkan kita untuk mengetahui apakah URL ini terdaftar di sistem dan jika layanan yang diwakilinya dapat menggunakan layanan dari server SSO.



Berikut adalah tampilan daftar URL untuk layanan yang diizinkan menggunakan server SSO:



const alloweOrigin = {
"http://consumer.ankuranand.in:3020": true,
"http://consumertwo.ankuranand.in:3030": true,
"http://test.tangledvibes.com:3080": true,
"http://blog.tangledvibes.com:3080": fasle,
};


LANGKAH 3



Pengguna memasukkan nama pengguna dan kata sandi yang dikirim ke server SSO dalam permintaan login.





Halaman masuk



LANGKAH 4



Server otentikasi SSO memverifikasi informasi pengguna dan membuat sesi antara dirinya dan pengguna. Inilah yang disebut "sesi global". Token otorisasi segera dibuat. Token adalah serangkaian karakter acak. Bagaimana tepatnya string ini dihasilkan tidak masalah. Hal utama adalah baris serupa tidak diulang untuk pengguna yang berbeda, dan baris seperti itu akan sulit untuk dipalsukan.



LANGKAH 5



Server SSO mengambil token otorisasi dan meneruskannya ke tempat asal pengguna yang baru masuk (yaitu, meneruskan token ke konsumen SSO).



const doLogin = (req, res, next) => {
  //         .
  //         , 
  // userDB -   ,   ,   
  const { email, password } = req.body;
  if (!(userDB[email] && password === userDB[email].password)) {
    return res.status(404).json({ message: "Invalid email and password" });
  }

  //     
  const { serviceURL } = req.query;
  const id = encodedId();
  req.session.user = id;
  sessionUser[id] = email;
  if (serviceURL == null) {
    return res.redirect("/");
  }
  const url = new URL(serviceURL);
  const intrmid = encodedId();
  storeApplicationInCache(url.origin, id, intrmid);
  return res.redirect(`${serviceURL}?ssoToken=${intrmid}`);
};


Sekali lagi, beberapa catatan keamanan:



  • Token ini harus selalu dianggap sebagai mekanisme perantara, ini digunakan untuk mendapatkan token lain.
  • Jika Anda menggunakan JWT sebagai token perantara, cobalah untuk tidak memasukkan rahasia di dalamnya.


LANGKAH 6



Konsumen SSO menerima token dan menghubungi server SSO untuk memverifikasi token tersebut. Server memeriksa token dan mengembalikan token lain dengan informasi pengguna. Token ini digunakan oleh konsumen SSO untuk membuat sesi dengan pengguna. Sesi ini disebut lokal.



Berikut adalah kode middleware yang digunakan di konsumen SSO berbasis Express:



const ssoRedirect = () => {
  return async function(req, res, next) {
    // ,    req queryParameter,  ssoToken,
    //  ,    .
    const { ssoToken } = req.query;
    if (ssoToken != null) {
      //   ssoToken   ,  .
      const redirectURL = url.parse(req.url).pathname;
      try {
        const response = await axios.get(
          `${ssoServerJWTURL}?ssoToken=${ssoToken}`,
          {
            headers: {
              Authorization: "Bearer l1Q7zkOL59cRqWBkQ12ZiGVW2DBL"
            }
          }
        );
        const { token } = response.data;
        const decoded = await verifyJwtToken(token);
        //      jwt,  
        // global-session-id  id ,  
        //         .
        req.session.user = decoded;
      } catch (err) {
        return next(err);
      }

      return res.redirect(`${redirectURL}`);
    }

    return next();
  };
};


Setelah menerima permintaan dari konsumen SSO, server memeriksa keberadaan dan tanggal kedaluwarsa token. Token terverifikasi dianggap valid.



Dalam kasus kami, server SSO, setelah verifikasi token berhasil, mengembalikan JWT yang ditandatangani dengan informasi tentang pengguna.



const verifySsoToken = async (req, res, next) => {
  const appToken = appTokenFromRequest(req);
  const { ssoToken } = req.query;
  //        ssoToken .
  //  ssoToken    - ,   .
  if (
    appToken == null ||
    ssoToken == null ||
    intrmTokenCache[ssoToken] == null
  ) {
    return res.status(400).json({ message: "badRequest" });
  }

  //  appToken  -     
  const appName = intrmTokenCache[ssoToken][1];
  const globalSessionToken = intrmTokenCache[ssoToken][0];
  //  appToken   ,   SSO-        
  if (
    appToken !== appTokenDB[appName] ||
    sessionApp[globalSessionToken][appName] !== true
  ) {
    return res.status(403).json({ message: "Unauthorized" });
  }
  // ,     
  const payload = generatePayload(ssoToken);

  const token = await genJwtToken(payload);
  //    ,     
  delete intrmTokenCache[ssoToken];
  return res.status(200).json({ token });
};


Berikut beberapa catatan keamanan.



  • Semua aplikasi yang akan menggunakan server ini untuk otentikasi harus terdaftar dengan server SSO. Mereka perlu diberi kode yang akan digunakan untuk memverifikasi mereka ketika mereka membuat permintaan ke server. Hal ini memungkinkan tingkat keamanan yang lebih tinggi saat berkomunikasi antara server SSO dan konsumen SSO.
  • Anda dapat membuat file rsa "pribadi" dan "publik" yang berbeda untuk setiap aplikasi dan membiarkan masing-masing memverifikasi JWT mereka sendiri dengan kunci publiknya masing-masing.


Selain itu, Anda dapat menentukan kebijakan keamanan tingkat aplikasi dan mengatur penyimpanan terpusatnya:



const userDB = {
  "info@ankuranand.com": {
    password: "test",
    userId: encodedId(), //   ,         .
    appPolicy: {
      sso_consumer: { role: "admin", shareEmail: true },
      simple_sso_consumer: { role: "user", shareEmail: false }
    }
  }
};


Setelah pengguna berhasil masuk ke sistem, sesi dibuat antara dia dan server SSO, serta antara dia dan setiap subsistem. Sesi yang dibuat antara pengguna dan server SSO disebut sesi global. Sesi yang dibuat antara pengguna dan subsistem yang menyediakan beberapa layanan kepada pengguna disebut sesi lokal. Setelah sesi lokal dibuat, pengguna akan dapat bekerja dengan sumber daya subsistem tertutup untuk sumber daya asing.





Menyiapkan sesi lokal dan global



Tur singkat tentang konsumen SSO dan server SSO



Mari kita ikuti tur singkat tentang konsumen SSO dan fungsionalitas server SSO.



โ– Konsumen SSO



  1. Subsistem konsumen SSO tidak mengotentikasi pengguna dengan mengarahkan pengguna ke server SSO.
  2. Subsistem ini menerima token yang diteruskan kepadanya oleh server SSO.
  3. Ini berinteraksi dengan server untuk memverifikasi validitas token.
  4. Dia menerima JWT dan memvalidasi token ini menggunakan kunci publik.
  5. Subsistem ini membuat sesi lokal.


โ–Server SSO



  1. Server SSO memvalidasi informasi login pengguna.
  2. Server membuat sesi global.
  3. Ini menciptakan token otorisasi.
  4. Token otorisasi dikirim ke konsumen SSO.
  5. Server memverifikasi validitas token yang diteruskan kepadanya oleh konsumen SSO.
  6. Server mengirimkan SSO JWT ke konsumen dengan informasi pengguna.


Organisasi logout terpusat



Mirip dengan bagaimana SSO diimplementasikan, Anda dapat mengimplementasikan teknologi SSO. Di sini Anda hanya perlu mempertimbangkan pertimbangan berikut:



  1. Jika ada sesi lokal, sesi global juga harus ada.
  2. Jika sesi global ada, itu tidak berarti bahwa sesi lokal ada.
  3. Jika sesi lokal dihancurkan, sesi global juga harus dihancurkan.


Hasil



Akibatnya, perlu dicatat bahwa ada banyak implementasi siap pakai dari teknologi sistem masuk tunggal yang dapat Anda integrasikan ke dalam sistem Anda. Mereka semua memiliki kelebihan dan kekurangan masing-masing. Mengembangkan sistem semacam itu secara mandiri, dari awal, adalah proses berulang, di mana Anda perlu menganalisis karakteristik masing-masing sistem. Ini termasuk metode login, penyimpanan informasi pengguna, sinkronisasi data, dan lainnya.



Apakah proyek Anda menggunakan mekanisme SSO?






All Articles