Puncte:1

Înregistrarea numelui de utilizator în jurnalul de acces KeyCloak

drapel br

În KeyCLoak 15.0 (adică WildFly 23.0), încerc să configurez jurnalul de acces pentru a include și numele de utilizator (sau orice ID al utilizatorului) atunci când un utilizator este conectat. keycloak/standalone/configuration/standalone.xml, am configurat XML:/server/profil/subsistem[@xmlns="urn:jboss:domain:undertow:12.0"]/server/gazdă/access-log/@pattern pattern="%h %l %u %t "%r" %s/%S %b %T %I "%{i,User-Agent}""

Jurnalul este tipărit corect în fișierul pe care l-am configurat. Cu toate acestea, valoarea de %u sau %{REMOTE_USER} este întotdeauna gol (adică -).

Singura modalitate de a înregistra un ID de utilizator pe care l-am găsit a fost înregistrarea valorii cookie-ului de sesiune %{c,KEYCLOAK_SESSION} (contine domeniu/ID-utilizator/secret). Ceea ce nu este o idee bună de făcut în producție.

Aveți idee despre cum să vă înregistrați numele de utilizator sau ID-ul de utilizator în jurnal de acces?

Este o eroare KeyCLoak care %u sau %{REMOTE_USER} este gol chiar și atunci când există o sesiune de utilizator activă în KeyCloak? Sau este posibil în KeyCLoak să configurați valoarea atributului utilizatorului REMOTE_USER?

Alternativ, cum să puneți ID-ul utilizatorului într-un antet pentru a utiliza unul dintre următoarele?

  • %{i,xxx} pentru anteturile primite
  • %{o,xxx} pentru anteturile de răspuns de ieșire
  • %{c,xxx} pentru un anumit cookie
  • %{r,xxx} unde xxx este un atribut în ServletRequest
  • %{s,xxx} unde xxx este un atribut în HttpSession

Printre altele, le-am încercat pe acestea. Niciunul dintre ei nu era populat.

%{s,utilizator} 
%{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}
Puncte:2
drapel jp

Am trecut peste o problemă similară (clientul meu mi-a cerut să înregistrez ID-ul clientului) și am ajuns să caut o soluție. Privind codul sursă și modul în care este populat jurnalul de acces, vă pot spune că există un decalaj destul de mare între locul în care se formează jurnalul și locul în care se realizează munca.

Dacă aruncați o privire pe Keycloak, se bazează pe Wildfly, care folosește Undertow pentru a găzdui funcționalitatea serverului http. În timp ce intrarea în jurnalul de acces este emisă odată ce cererea a fost servită, există puține lacune și abstracții care complică lucrurile.

Din perspectiva software-ului, există handler undertow, apoi servlet, apoi servlet Restasy, apoi aplicație keycloak și resurse specifice. Când utilizați utilizatorul Keycloak sau consola de administrare, atunci în majoritatea locurilor este un client „subțire” care este redat de un browser web. Și acest browser numește rest resource.

Dacă doriți să obțineți destul de des informații legate de utilizator, acestea nu vor fi găsite în sesiune, deoarece cea mai mare parte a muncii efectuate de Kecloak este emiterea de token-uri în numele utilizatorilor. În mod formal, clientul care trimite cererea acționează în numele utilizatorului, ceea ce înseamnă că nu este o informație explicită disponibilă pentru fiecare solicitare primită. În plus, majoritatea resurselor de odihnă, prin definiție, sunt apatride, ceea ce înseamnă că funcționează cumva cu utilizatorul, dar nu populează prea mult sesiunea. Doar o parte pentru care puteți conta pe accesul la informațiile utilizatorului este atunci când utilizatorul se conectează și face ceva în consola contului de utilizator. Pe lângă asta, ar putea fi o luptă pierdută, deoarece resursele keycloak care emit token-uri în majoritatea cazurilor se vor ocupa de sesiuni legate de client sau client.

La obiect - am ajuns la punctul în care am localizat locul care face analiza formatului jurnalului de acces. Se bazează pe Undertow ExchangeAtribute idee care vă permite să vă aduceți propria macrocomandă pentru jurnal. Această macrocomandă poate fi utilizată fie pentru a traversa structurile de memorie în căutarea informațiilor necesare. Pentru mine a fost un client_id care făcea treaba. Pentru asta am ajuns la implementarea unui FormAttribute. Încă trebuie să găsesc o modalitate de a-l conecta, dar din perspectiva testului unitar deja „a făcut clic”, vezi cât de de bază este codul:

pachetul org.code_house.wildfly.stuff.undertow.attributes;
// amintiți-vă să creați META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder
// cu linia care conține numele clasei, de exemplu.
// org.code_house.wildfly.stuff.undertow.attributes.FormAttribute$Builder

/**
 * Expuneți parametrii formularului în cadrul atributelor de schimb care pot fi autentificate în jurnalul de acces.
 * Folosiți %{F,*} pentru a descărca toți parametrii sau %{F,client_id} pentru a reda selectat din câmp.
 *
 * @autor Åukasz Dywicki @ code-house.org
 **/
clasa publică FormAttribute implementează ExchangeAttribute {

  Private final String paramName;

  public FormAttribute(String paramName) {
    this.paramName = paramName;
  }

  @Trece peste
  public String readAttribute(HttpServerExchange exchange) {
    FormData formData = exchange.getAttachment(FormDataParser.FORM_DATA);
    dacă ("*".equals(paramName)) {
      returnează „” + formData;
    }
    return formData == null? "" : "" + formData.get(paramName);
  }

  @Trece peste
  public void writeAttribute(HttpServerExchange exchange, String newValue) aruncă ReadOnlyAttributeException {
    aruncă o nouă excepție ReadOnlyAttributeException ("Form", newValue);
  }

  Public static final class Builder implementează ExchangeAttributeBuilder {
    @Trece peste
    public String name() {
      returnează „formular”;
    }

    @Trece peste
    public ExchangeAttribute build (semnal String final) {
      if (token.startsWith("%{F,") && token.endsWith("}")) {
        final String paramName = token.substring(4, token.length() - 1);
        returnează nou FormAttribute(paramName);
      }
      returnează nul;
    }

    @Trece peste
    public int priority() {
      returnează 0;
    }
  }
}

Punctul principal - prin utilizarea atributului de formular la valoarea de înregistrare introdusă în câmpul „nume utilizator” al formularului de conectare pentru a obține „cine”, atunci puteți combina acest lucru cu cookie-ul de sesiune care va fi reținut de browser. Prin fuziunea de bază a doi ași de mai sus puteți obține rezultatul necesar. Folosind planul de mai sus, puteți implementa propriul lucru și puteți urmări jetoanele și alte lucruri care vă vor permite să vă construiți aplicația.

S-ar putea să actualizez răspunsul atunci când găsesc o logică adeziv pentru a injecta în mod corespunzător un atribut suplimentar în formatul de jurnal în undertow. EDIT: Doar o modalitate pe care am găsit-o până acum de a injecta atribute suplimentare este prin a le copia în $JBOSS_HOME/modules/system/layers/base/org/wildfly/extension/undertow/main/ si actualizare module.xml în acest director:

<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>

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.