5.2. 클라이언트 시작 계정 연결
일부 애플리케이션은 Facebook과 같은 소셜 공급자와 통합하려고 하지만 이러한 소셜 공급자를 통해 로그인할 수 있는 옵션을 제공하지 않으려고 합니다. Red Hat Single Sign-On은 애플리케이션이 기존 사용자 계정을 특정 외부 IDP에 연결하는 데 사용할 수 있는 브라우저 기반 API를 제공합니다. 이를 클라이언트 시작 계정 연결이라고 합니다. 계정 링크는 OIDC 애플리케이션에서만 시작할 수 있습니다.
애플리케이션이 작동하는 방식은 사용자의 브라우저를 Red Hat Single Sign-On 서버의 URL로 전달하여 사용자의 계정을 특정 외부 공급자(예: Facebook)에 연결하도록 요청하는 것입니다. 서버는 외부 공급자를 사용한 로그인을 시작합니다. 브라우저가 외부 공급자에서 로그인되고 다시 서버로 리디렉션됩니다. 서버는 링크를 설정하고 확인과 함께 애플리케이션으로 다시 리디렉션합니다.
이 프로토콜을 시작하기 전에 클라이언트 애플리케이션에서 충족해야 하는 몇 가지 사전 조건이 있습니다.
- 원하는 ID 공급자는 관리 콘솔에서 사용자 영역에 대해 구성하고 활성화해야 합니다.
- 사용자 계정이 이미 OIDC 프로토콜을 통해 기존 사용자로 로그인되어 있어야 합니다.
-
사용자에게
account.manage-account
또는account.manage-account-links
역할 매핑이 있어야 합니다. - 애플리케이션에 액세스 토큰 내에서 해당 역할에 대한 범위를 부여해야 합니다.
- 애플리케이션은 리디렉션 URL을 생성하기 위해 내부 정보가 필요하므로 액세스 토큰에 액세스할 수 있어야 합니다.
로그인을 시작하려면 애플리케이션이 URL을 작성하고 사용자 브라우저를 이 URL로 리디렉션해야 합니다. URL은 다음과 같습니다.
/{auth-server-root}/auth/realms/{realm}/broker/{provider}/link?client_id={id}&redirect_uri={uri}&nonce={nonce}&hash={hash}
다음은 각 경로 및 쿼리 매개 변수에 대한 설명입니다.
- 공급자
-
이는 관리 콘솔의
ID 공급자 섹션에 정의한 외부 IDP의 공급자
별칭입니다. - client_id
- 애플리케이션의 OIDC 클라이언트 ID입니다. 관리 콘솔에서 애플리케이션을 클라이언트로 등록할 때 이 클라이언트 ID를 지정해야 했습니다.
- redirect_uri
- 계정 링크가 설정된 후 리디렉션하려는 애플리케이션 콜백 URL입니다. 클라이언트 리디렉션 URI 패턴이어야 합니다. 즉, 관리 콘솔에서 클라이언트를 등록할 때 정의한 유효한 URL 패턴 중 하나와 일치해야 합니다.
- nonce
- 애플리케이션에서 생성해야 하는 임의의 문자열입니다.
- hash
-
Base64 URL 인코딩 해시입니다. 이 해시는 Base64 URL에서
nonce
+token.getSessionState()
+token.getIssuedFor()
+공급자
의 SHA_256 해시를 인코딩하여 생성합니다. 토큰 변수는 OIDC 액세스 토큰에서 가져옵니다. 기본적으로 임의의 번호, 사용자 세션 ID, 클라이언트 ID 및 액세스하려는 ID 공급자 별칭을 해시하고 있습니다.
다음은 계정 링크를 설정하는 URL을 생성하는 Java Servlet 코드의 예입니다.
KeycloakSecurityContext session = (KeycloakSecurityContext) httpServletRequest.getAttribute(KeycloakSecurityContext.class.getName()); AccessToken token = session.getToken(); String clientId = token.getIssuedFor(); String nonce = UUID.randomUUID().toString(); MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } String input = nonce + token.getSessionState() + clientId + provider; byte[] check = md.digest(input.getBytes(StandardCharsets.UTF_8)); String hash = Base64Url.encode(check); request.getSession().setAttribute("hash", hash); String redirectUri = ...; String accountLinkUrl = KeycloakUriBuilder.fromUri(authServerRootUrl) .path("/auth/realms/{realm}/broker/{provider}/link") .queryParam("nonce", nonce) .queryParam("hash", hash) .queryParam("client_id", clientId) .queryParam("redirect_uri", redirectUri).build(realm, provider).toString();
이 해시가 포함된 이유는 무엇입니까? 이를 통해 auth 서버는 클라이언트 애플리케이션이 요청을 시작했으며 다른 악성 앱이 특정 공급자에게 연결되도록 무작위로 요청하지 않았습니다. 인증 서버는 먼저 로그인 시 설정된 SSO 쿠키를 확인하여 사용자가 로그인했는지 확인합니다. 그런 다음 현재 로그인을 기반으로 해시를 다시 생성하고 애플리케이션에서 보낸 해시와 일치하려고 합니다.
계정이 연결되면 auth 서버는 redirect_uri
로 리디렉션됩니다. 링크 요청을 처리하는 데 문제가 있는 경우 auth 서버는 redirect_uri
로 리디렉션할 수도 있습니다. 브라우저가 애플리케이션으로 리디렉션되는 대신 오류 페이지를 종료할 수 있습니다. 오류 조건이 있고 인증 서버가 클라이언트 애플리케이션으로 다시 리디렉션할 수 있을 만큼 안전한 것으로 간주하는 경우 추가 오류
쿼리 매개변수가 redirect_uri
에 추가됩니다.
이 API는 애플리케이션이 요청을 시작한 것을 보장하지만 이 작업에 대한 CSRF 공격을 완전히 방지하지는 않습니다. 애플리케이션은 여전히 CSRF 공격 대상이 되는 CSRF 공격을 방지할 책임이 있습니다.
5.2.1. 외부 토큰 새로 고침
공급자에 로그인하여 생성된 외부 토큰(예: Facebook 또는 GitHub 토큰)을 사용하는 경우 계정을 연결하는 API를 다시 초기화하여 이 토큰을 새로 고칠 수 있습니다.