KeyCLoak 15.0(WildFly 23.0)에서는 사용자가 로그인할 때 사용자 이름(또는 사용자의 ID)도 포함하도록 액세스 로그를 구성하려고 합니다. 에서 keycloak/standalone/configuration/standalone.xml
구성했습니다.
XML:/server/profile/subsystem[@xmlns="urn:jboss:domain:undertow:12.0"]/server/host/access-log/@pattern
pattern="%h %l %u %t "%r" %s/%S %b %T %I "%{i,User-Agent}""
내가 구성한 파일에 로그가 올바르게 인쇄됩니다. 그러나 %u
or 의 값은 %{REMOTE_USER}
항상 비어 있습니다(즉, -
).
내가 찾은 일부 사용자 ID를 기록하는 유일한 방법은 %{c,KEYCLOAK_SESSION}
(포함 realm/user-ID/secret
)을 사용하여 세션 쿠키 값을 기록하는 것이었습니다. 프로덕션에서 수행하는 것은 좋은 생각이 아닙니다.
액세스 로그에 사용자 이름이나 사용자 ID를 기록하는 방법에 대한 아이디어가 있습니까?
KeyCloak에 활성 사용자 세션이 있는 경우에도 비어 있거나 비어 있는 %u
KeyCloak 버그입니까 ? %{REMOTE_USER}
아니면 KeyCLoak에서 어떤 사용자 속성 값이 들어갈지 구성할 수 있나요 REMOTE_USER
?
대안적으로, 다음 중 하나를 사용하기 위해 일부 헤더에 userID를 넣는 방법은 무엇입니까?
%{i,xxx}
수신 헤더의 경우%{o,xxx}
나가는 응답 헤더의 경우%{c,xxx}
특정 쿠키에 대해%{r,xxx}
여기서 xxx는 ServletRequest의 속성입니다.%{s,xxx}
여기서 xxx는 HttpSession의 속성입니다.
그 중에서도 나는 이것을 시도했습니다. 그 중 누구도 사람이 살지 않았습니다.
%{s,user}
%{s,userId}
%{s,client_id}
%{s,USER_ID}
%{s,USER}
%{s,org.keycloak.adapters.spi.KeycloakAccount}
%{s,KeycloakAccount}
%{s,org.keycloak.adapters.tomcat.CatalinaSessionTokenStore.SerializableKeycloakAccount}
%{s,SerializableKeycloakAccount}
%{s,org.keycloak.adapters.saml.SamlSession}
%{s,SamlSession}
%{s,org.keycloak.adapters.undertow.KeycloakUndertowAccount}
%{s,KeycloakUndertowAccount}
%{s,org.keycloak.KeycloakSecurityContext}
%{s,KeycloakSecurityContext}
%{s,io.undertow.servlet.util.SavedRequest}
%{s,SavedRequest}
%{r,tokenInfo}
%{r,KeycloakSecurityContext}
%{r,ElytronHttpFacade}
%{r,AdapterDeploymentContext}
%{r,TOKEN_STORE_NOTE}
답변1
비슷한 문제(내 고객이 나에게 클라이언트 ID를 기록하라고 요청함)가 발생하여 결국 해결책을 찾았습니다. 소스 코드와 액세스 로그가 어떻게 채워지는지 살펴보면 로그가 생성되는 위치와 실제 작업이 수행되는 위치 사이에 꽤 큰 차이가 있음을 알 수 있습니다.
Keycloak을 살펴보면 Undertow를 사용하여 http 서버 기능을 호스팅하는 Wildfly를 기반으로 합니다. 요청이 처리되면 액세스 로그 항목이 내보내지지만 상황을 복잡하게 만드는 간격과 추상화가 거의 없습니다.
소프트웨어 관점에서 보면 Undertow 핸들러, 서블릿, Resteasy 서블릿, Keycloak 애플리케이션 및 특정 리소스가 있습니다. Keycloak 사용자 또는 관리 콘솔을 사용하는 경우 대부분의 경우 웹 브라우저에서 렌더링되는 "씬" 클라이언트입니다. 그리고 이 브라우저는 나머지 리소스를 호출합니다.
사용자 관련 정보를 자주 얻으려는 경우 세션에서 찾을 수 없습니다. Kecloak이 수행하는 대부분의 작업은 사용자를 대신하여 토큰을 발행하기 때문입니다. 공식적으로 요청을 전달하는 클라이언트는 사용자를 대신하여 작동합니다. 이는 들어오는 각 요청에 대해 사용할 수 있는 명시적인 정보가 아님을 의미합니다. 또한 대부분의 나머지 리소스는 상태 비저장(stateless)입니다. 즉, 사용자와 함께 작동하지만 세션을 많이 채우지는 않습니다. 사용자 정보에 대한 액세스를 기대할 수 있는 부분은 사용자가 실제로 로그인하여 사용자 계정 콘솔 내에서 작업을 수행하는 경우입니다. 게다가 대부분의 경우 토큰을 발행하는 keycloak 리소스가 클라이언트 또는 클라이언트 관련 세션을 처리하므로 전투에서 패배할 수 있습니다.
요점 - 액세스 로그 형식을 구문 분석하는 장소를 찾았습니다. 이는 ExchangeAttribute
로그에 자신만의 매크로를 가져올 수 있는 Undertow 아이디어를 기반으로 합니다 . 이 매크로는 필요한 정보를 찾기 위해 메모리 구조를 탐색하는 데 사용될 수 있습니다. 나에게는 작업을 수행하는 client_id였습니다. 이를 위해 나는 FormAttribute
. 여전히 연결하는 방법을 찾아야 하지만 단위 테스트 관점에서 이미 "클릭"되었습니다. 기본 코드가 어떻게 되는지 확인하세요.
package org.code_house.wildfly.stuff.undertow.attributes;
// remember to create META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder
// with line containing class name, ie.
// org.code_house.wildfly.stuff.undertow.attributes.FormAttribute$Builder
/**
* Expose form parameters within exchange attributes which can be logged in access log.
* Use %{F,*} to dump all params or %{F,client_id} to render selected from field.
*
* @author Łukasz Dywicki @ code-house.org
**/
public class FormAttribute implements ExchangeAttribute {
private final String paramName;
public FormAttribute(String paramName) {
this.paramName = paramName;
}
@Override
public String readAttribute(HttpServerExchange exchange) {
FormData formData = exchange.getAttachment(FormDataParser.FORM_DATA);
if ("*".equals(paramName)) {
return "" + formData;
}
return formData == null ? "" : "" + formData.get(paramName);
}
@Override
public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
throw new ReadOnlyAttributeException("Form", newValue);
}
public static final class Builder implements ExchangeAttributeBuilder {
@Override
public String name() {
return "form";
}
@Override
public ExchangeAttribute build(final String token) {
if (token.startsWith("%{F,") && token.endsWith("}")) {
final String paramName = token.substring(4, token.length() - 1);
return new FormAttribute(paramName);
}
return null;
}
@Override
public int priority() {
return 0;
}
}
}
주요 요점 - 양식 속성을 사용하여 로그인 양식의 "사용자 이름" 필드에 입력된 값을 기록하여 "누구"를 얻은 다음 이를 브라우저에 유지되는 세션 쿠키와 결합할 수 있습니다. 위의 두 에이스를 기본적으로 병합하면 필요한 결과를 얻을 수 있습니다. 위의 청사진을 사용하면 자신만의 것을 구현하고 애플리케이션을 구축할 수 있는 토큰 및 기타 사항을 추적할 수 있습니다.
언더토우의 로그 형식에 추가 속성을 적절하게 삽입하는 글루 로직을 찾으면 답변을 업데이트할 수 있습니다. 편집: 추가 속성을 삽입하기 위해 지금까지 찾은 한 가지 방법은 해당 속성을 이 디렉터리에 복사 $JBOSS_HOME/modules/system/layers/base/org/wildfly/extension/undertow/main/
하고 업데이트하는 것 입니다.module.xml
<module name="org.wildfly.extension.undertow" xmlns="urn:jboss:module:1.5">
...
<resources>
<resource-root path="wildfly-undertow-20.0.1.Final.jar"/>
<!-- put here name of jar you made -->
<resource-root path="undertow-client-request-filter-1.0.0-SNAPSHOT.jar"/>
</resources>
...
</module>