Laden...

[gelöst] WCF - CustomIdentity in CustomValidator

Erstellt von RaphaelH vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.162 Views
R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren
[gelöst] WCF - CustomIdentity in CustomValidator

Hallo zusammen,

Ich hätte da mal ne Frage.. Ich komm einfach nicht drauf..

Also ich habe einen WCF Service mit net.Tcp Binding mit Message/UserName Security welche einen eigenen UserNamePasswordValidator besitzt.

Wenn ich die Verbindung aus Client aufbaue, wird ja die Methode Validate ausgeführt. Diese soll dann über meine andere static Klasse Authentication die authentifizierung übernehmen. Soweit so gut.

Meine Authentication Klasse hat die public Methode Authenticate, diese gibt ein enum Wert zurück, dies dient dazu, da ich 2 Stellen haben wo gegen ich die Authentifizierung mache, um zu wissen wo er sich denn dann authentifizieren konnte. (In diesem Falle Active Directory und eine andere Software)

Diesen Enum Wert würde ich dann gerne in Thread.CurrentPrincipal.Identity speichern, dazu habe ich ein CustomIdentity erstellt mit Variable Level ( darin soll gespeichert werden ob Active Directory, Software oder beides). Dies brauche ich dafür um später die Rollen richtig zuzuordnen, da ich das Passwort nicht dauerhaft mir irgendwo im Speicher ablegen möchte! (Auch Sicherheitstechnisch unschön)

Hier mal der Code wo dann mir die Exception geworfen wird (Die Zeile mit Kommentar):


public override void Validate(string userName, string password)
{
    CustomIdentity identity = Thread.CurrentPrincipal.Identity as CustomIdentity;
    try
    {
        identity.Level = Authentication.Authenticate(userName, password); //Hier wird die Exception geworfen
    }
    catch (BadLoginException)
    {
        throw new FaultException("Falscher Benutzername oder Password");
    }
}

Im WCF-Trace steht dann > Fehlermeldung:

Object reference not set to an instance of an object. Ich denke dies rührt daher, da in diesem Moment, die Identity im Thread noch nicht initialisiert worden ist.

Aber ich kann diese ja nicht auf CustomIdentity initialsieren, da dies ja eine interface ist..

Ich komm einfach nicht drauf.. 😕

Danke euch schonmal! 😃

Wenn noch Fragen offen sind, einfach rein hier!

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Man könnte diese Variable die ich benötige ein static Dictionary schreiben und verknüpfen an irgendeine ID (Gibt es zu diesem Zeitpunkt eine eindeutige ID?) und dann später über die ID auf die Variable zurückgreifen..

Aber ich weiss nicht ob dies die schönste Möglichkeit ist..

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

die Thread.CurrentPrincipal.Identity würde ich so nicht setzen, denn der Thread kann auch anderswertig wieder verwendet werden. Würdest du das so machen, so sollte am Ende der Aktionen die Identity wieder zurückgesetzt werden.

So wie ich es sehe gehts dir also um eine Session-Tabelle, die konkrete Umsetzung mal außer acht gelassen. Hier könntest du, wie du auch in der Vorantwort geschrieben hast, eine ID generieren (new Guid()) und diese zum Client senden. Der Client muss dann diese Session-ID bei jedem Aufruf mitübertragen und somit kann alles nötige aus der Session-Tabelle gelesen werden.

Die Session-Tabelle könntest du In-Memory als Dictionary anlegen, in einer Datenbank wenns, ....

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Mit Thread klappt dies überhaupt nicht..

Wenn ich eine Identity im Thread initialisiere, gibts diese Identity nachher im Evaluate (Wo das AuthenticationLevel gesetzte wird) nicht mehr.. '(Wahrscheinlich anderer Thread)

Guid kann ich generieren, kann ich ebenfalls in ein Dictionary schreiben mit AuthenticationLevel und Username.. Jedoch wie kann ich dem Client diese Guid aus dem CustomValidator senden?

Trotzdessen, finde ich diese Methode etwas unschön.. Schöner wäre ein Context der vom Client direkt am Anfang initialisiert wird und auf diesen ich überall zugreifen kann pro Client.

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

Jedoch wie kann ich dem Client diese Guid aus dem CustomValidator senden?

Als Rückgabewert, out-Parameter einer Methode die der Client aufruft. Entweder implizit od. explizit über eine z.B. Connect-Methode.

Schöner wäre ein Context der vom Client direkt am Anfang initialisiert wird und auf diesen ich überall zugreifen kann pro Client.

WCF bietet auch Unterstützung für Sessions. Schau dir mal Using Sessions an, vllt. ist das passend für dich.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Ich benutze Sessions 😃

Jedoch, wie kann ich auf diesen Context aus UserNamePasswordValidator zugreifen?

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

wenn die Service-Instanz PerSession ist, dann kannst du diesen in Feld ablegen und darauf innerhalb der Service-Klasse zugreifen.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Richtig, ich kann innerhalb der Service-Klasse zugreifen.

Jedoch wie soll ich diese Variable von außerhalb setzen, bzw. auslesen?

UserNamePasswordValidator ist ja nicht in der Service-Klasse und IPrincipal.IsInRole(string role) wo ich dann die AuthenticationLevel Variable brauche, ist auch nicht in der Service-Klasse.

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

das ist ja nix anderes als sonst bei Klassen auch: eine Eigenschaft od. Methode um das Feld öffentlich zugänglich zu machen.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Vielleicht reden wir aneinander vorbei 😕.. Ich versuch nochmal etwas von vorn..

Also,

-Client verbindet
-Credentials werden überprüft -> daraus erhalte ich einen Wert
-Diesen Wert muss pro Session irgendwo speichern
-Diesen Wert muss ich dann wenn IPrincipal.IsInRole ausgeführt wird, wieder abrufen können.

Problem dabei, ich kann soviele public Felder in meinem Contract machen wie ich möchte, jedoch wird dieser Contract per Client initialisiert, heißt nicht static, wie soll ich nun diesen Wert ändern können? Gleiche gilt für IPrincipal..

Gibt es nicht Etwas wie OperationContext.Current, woraus ich weiss welcher Client es ist oder soetwas in die Richtung?

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

Gibt es nicht Etwas wie OperationContext.Current, woraus ich weiss welcher Client es ist

das gibts über OperationContext.SessionId Property (System.ServiceModel) und das kannst du mit der Session-Tabelle verwenden um die gespeicherten Infos über den Client auslesen.

-Diesen Wert muss pro Session irgendwo speichern
-Diesen Wert muss ich dann wenn IPrincipal.IsInRole ausgeführt wird, wieder abrufen können.

Die Session-ID speicherst du zu Beginn der Session in das private Feld der Service-Klasse und erstellst in der Session-Tabelle den Eintrag. Somit kannst du während der Session immer darauf zugreifen. Am Ende der Session entfernst du den Eintrag aus der Session-Tabelle.

Ich sehe ehrlich gesagt nicht wo das Problem liegen soll.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Wie du sagst, ich habe in meiner static Klasse Authentication ein Dictionary erstelle <string, Authenticationlevel>

Dann würde ich im UserNamePasswordValidator einen Eintrag hinzufügen. Jedoch Da gibt er mir die Exception > Fehlermeldung:

Object reference not set to an instance of an object . Wahrscheinlich weil OperationContext nicht initialisiert worden ist..

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Ich denke so kann man das nicht umsetzen..

Gibt es eine Möglichkeit den Verlauf der WCF Authentication/Authorization nachzuvollziehen? Irgendwie mit Decompiler? Sodass ich eventuell einige Methoden überschreibe und es eventuell so hinbekomme?

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo RaphaelH,

Gibt es eine Möglichkeit den Verlauf der WCF Authentication/Authorization nachzuvollziehen? Irgendwie mit Decompiler?

Mti dem Reflector durchwühlen od. mit VS und Source-Code-Stepping beim Debugging durchgehen.

Aber warum sollte es so nicht umsetzbar sein? Dieses Vorgehen war auch beim Remoting nicht viel anders. Es ist doch ziemlich straight-forward, oder nicht?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Probleme :

-Username ist bei mir nicht eindeutig (Da dieser öfter als einmal vorkommen kann)
-OperationContext wird erst später initialisiert
-UserNamePasswordValidator ist der einzige Ort wo ich das Passwort habe und der User erst damit wirklich eindeutig ist!

R
RaphaelH Themenstarter:in
65 Beiträge seit 2011
vor 12 Jahren

Okay,

Ich habe es gelöst bekommen..

Musste eigenen ServiceCredentials Type erstellen, welcher nen eigenen ServiceCredentialsSecurityTokenManager aufruft, dieser erstellt nen eigenen UserNameSecurityTokenAuthenticator, dieser erstellt meinen eigenen UserNamePasswordValidator wo ich ne eigene Methode mit meinem Rückgabewert erstellt habe.

Alles in eine eigene AuthorizationPolicy und voila! 😃

Danke trotzdem!