From e1b75074b501d2d3e0100d1170b3edef8a00799c Mon Sep 17 00:00:00 2001 From: Nicolas Werner <nicolas.werner@hotmail.de> Date: Sun, 6 Mar 2022 19:49:12 +0100 Subject: [PATCH] Support explicit IDPs --- include/mtx/responses/login.hpp | 35 +++++++++++++++++++++++++++++++ include/mtxclient/http/client.hpp | 4 ++-- lib/http/client.cpp | 5 +++-- lib/structs/responses/login.cpp | 12 ++++++++++- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/mtx/responses/login.hpp b/include/mtx/responses/login.hpp index 33a4b5e2d..fb93ee253 100644 --- a/include/mtx/responses/login.hpp +++ b/include/mtx/responses/login.hpp @@ -40,11 +40,46 @@ struct Login void from_json(const nlohmann::json &obj, Login &response); +//! Identity provider for SSO +struct IdentityProvider +{ + //! Optional UI hint for what kind of common SSO provider is being described in this IdP. Matrix + //! maintains a registry of identifiers in the matrix-doc repo to ensure clients and servers are + //! aligned on major/common brands. + //! + //! Clients should prefer the brand over the icon, when both are provided. Clients are not + //! required to support any particular brand, including those in the registry, though are + //! expected to be able to present any IdP based off the name/icon to the user regardless. + //! + //! Unregistered brands are permitted using the Common Namespaced Identifier Grammar, though + //! excluding the namespace requirements. For example, examplesso is a valid brand which is not + //! in the registry but still permitted. Servers should be mindful that clients might not + //! support their unregistered brand usage as intended by the server. + std::string brand; + //! Optional MXC URI to provide an image/icon representing the IdP. Intended to be shown + //! alongside the name if provided. + std::string icon; + //! Required: Opaque string chosen by the homeserver, uniquely identifying the IdP from other + //! IdPs the homeserver might support. Should be between 1 and 255 characters in length, + //! containing unreserved characters under RFC 3986 (ALPHA DIGIT "-" / "." / "_" / "~"). Clients + //! are not intended to parse or infer meaning from opaque strings. + std::string id; + //! Required: Human readable description for the IdP, intended to be shown to the user. + std::string name; +}; +void +from_json(const nlohmann::json &obj, IdentityProvider &response); + //! One supported login flow. struct LoginFlow { //! The authentication used for this flow. mtx::user_interactive::AuthType type; + + //! Optional identity providers (IdPs) to present to the user. These would appear (typically) as + //! distinct buttons for the user to interact with, and would map to the appropriate + //! IdP-dependent redirect endpoint for that IdP. + std::vector<IdentityProvider> identity_providers; }; void from_json(const nlohmann::json &obj, LoginFlow &response); diff --git a/include/mtxclient/http/client.hpp b/include/mtxclient/http/client.hpp index 019e96380..500d0cff6 100644 --- a/include/mtxclient/http/client.hpp +++ b/include/mtxclient/http/client.hpp @@ -255,9 +255,9 @@ public: //! Get the supported login flows void get_login(Callback<mtx::responses::LoginFlows> cb); - //! Get url to navigate to for sso login flow + //! Get url to navigate to for sso login flow, optionally preselecting an identity provider //! Open this in a browser - std::string login_sso_redirect(std::string redirectUrl); + std::string login_sso_redirect(std::string redirectUrl, const std::string &idp = ""); //! Lookup real server to connect to. //! Call set_server with the returned homeserver url after this void well_known(Callback<mtx::responses::WellKnown> cb); diff --git a/lib/http/client.cpp b/lib/http/client.cpp index d303a79d5..b73b47d6b 100644 --- a/lib/http/client.cpp +++ b/lib/http/client.cpp @@ -258,10 +258,11 @@ Client::get_login(Callback<mtx::responses::LoginFlows> cb) } std::string -Client::login_sso_redirect(std::string redirectUrl) +Client::login_sso_redirect(std::string redirectUrl, const std::string &idp) { + const std::string idp_suffix = idp.empty() ? idp : ("/" + mtx::client::utils::url_encode(idp)); return protocol_ + "://" + server() + ":" + std::to_string(port()) + - "/_matrix/client/r0/login/sso/redirect?" + + "/_matrix/client/r0/login/sso/redirect" + idp_suffix + "?" + mtx::client::utils::query_params({{"redirectUrl", redirectUrl}}); } diff --git a/lib/structs/responses/login.cpp b/lib/structs/responses/login.cpp index 5ceaf4c38..32e16b984 100644 --- a/lib/structs/responses/login.cpp +++ b/lib/structs/responses/login.cpp @@ -20,10 +20,20 @@ from_json(const nlohmann::json &obj, Login &response) response.well_known = obj.at("well_known").get<WellKnown>(); } +void +from_json(const nlohmann::json &obj, IdentityProvider &response) +{ + response.brand = obj.value("brand", ""); + response.icon = obj.value("icon", ""); + response.id = obj.at("id").get<std::string>(); + response.name = obj.at("name").get<std::string>(); +} + void from_json(const nlohmann::json &obj, LoginFlow &response) { - response.type = obj.at("type").get<std::string>(); + response.type = obj.at("type").get<std::string>(); + response.identity_providers = obj.value("identity_providers", std::vector<IdentityProvider>{}); } void from_json(const nlohmann::json &obj, LoginFlows &response) -- GitLab