Created
April 2, 2023 10:41
-
-
Save inspirit941/3aef972ac703a12655aab44779f16e45 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.inspirit941.remoteuserstorageprovider; | |
| import org.keycloak.component.ComponentModel; | |
| import org.keycloak.credential.CredentialInput; | |
| import org.keycloak.credential.CredentialInputValidator; | |
| import org.keycloak.credential.UserCredentialStore; | |
| import org.keycloak.models.KeycloakSession; | |
| import org.keycloak.models.RealmModel; | |
| import org.keycloak.models.UserModel; | |
| import org.keycloak.models.credential.PasswordCredentialModel; | |
| import org.keycloak.storage.UserStorageProvider; | |
| import org.keycloak.storage.adapter.AbstractUserAdapter; | |
| import org.keycloak.storage.user.UserLookupProvider; | |
| import java.util.stream.Collectors; | |
| public class RemoteUserStorageProvider implements UserStorageProvider, UserLookupProvider, CredentialInputValidator { | |
| private KeycloakSession session; | |
| private ComponentModel model; | |
| private UserApiService userApiService; | |
| public RemoteUserStorageProvider(KeycloakSession session, ComponentModel model, UserApiService userApiService) { | |
| this.session = session; | |
| this.model = model; | |
| this.userApiService = userApiService; | |
| } | |
| // UserStorageProvider 인터페이스만으로는 validate 같은 메소드를 override 형태로 제공하는 건 아님. | |
| // UserLookUpProvider로 getUserById / Email 등등이 가능하고 | |
| // CredentialInputValidator는 valid 검증. | |
| // 위 세 개는 keycloak이 사용자를 검증하기 위한 최소한의 인터페이스라고 보면 된다. | |
| @Override | |
| public void close() {} | |
| @Override | |
| public UserModel getUserById(String id, RealmModel realm) { return null; } | |
| @Override | |
| public UserModel getUserByUsername(String username, RealmModel realm) { | |
| // RESTEasy에서 send request to remote Web Service -> fetch userDetails. | |
| // 셋 중 하나라도 제대로 된 UserModel을 리턴한다면 로그인 성공으로 간주함 | |
| UserModel returnValue = null; | |
| var user = userApiService.getUserDetails(username); | |
| if (user != null) { | |
| returnValue = createUserModel(username, realm); | |
| } | |
| return returnValue; | |
| } | |
| private UserModel createUserModel(String username, RealmModel realm) { | |
| return new AbstractUserAdapter(session, realm, model) { | |
| @Override | |
| public String getUsername() { | |
| return username; | |
| } | |
| }; | |
| } | |
| @Override | |
| public UserModel getUserByEmail(String email, RealmModel realm) { | |
| return null; | |
| } | |
| @Override | |
| public boolean supportsCredentialType(String credentialType) { | |
| // 예시의 경우, credential 타입인 password를 지원하는지 확인할 용도 | |
| return PasswordCredentialModel.TYPE.equals(credentialType); | |
| } | |
| @Override | |
| public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) { | |
| // credential Type이 given user를 위한 게 맞는지 확인할 용도 | |
| // 공식 docs 내용 그대로 복사 | |
| if (!supportsCredentialType(credentialType)) return false; | |
| var result = getCredentialStore() | |
| .getStoredCredentialsByTypeStream(realm, user, credentialType) | |
| .collect(Collectors.toList()).isEmpty(); | |
| return !result; | |
| } | |
| private UserCredentialStore getCredentialStore() { | |
| return session.userCredentialManager(); | |
| } | |
| @Override | |
| public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) { | |
| // 사용자가 제공한 패스워드가 DB에 저장된 패스워드와 일치하는지를 확인하는 keycloak 호출 메소드. | |
| // 이 값이 true이면 user는 authenticated된 것임. | |
| // send a request to our remoteService Endpoint -> validate the provided password | |
| var result = userApiService.verifyUserPassword(user.getUsername(), credentialInput.getChallengeResponse()); | |
| // getUserChallengeResponse -> 패스워드를 리턴함 | |
| if (result == null) return false; | |
| return result.isResult(); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment