# Authentifizierung gegen DomainController



## franzy (5. Mrz 2021)

Hallo zusammen,

ich möchte mich gegen einen AD Authentifizieren. 
Ich habe dazu folgendes Programmiert:


```
LoginContext lc;
        
try
{   
    System.setProperty("java.security.krb5.realm", "domaineImDNS.de");
    System.setProperty("java.security.krb5.kdc", "ServerXYZ");

    lc = new LoginContext("", null, new StaticCallbackHandler("adname.dom\\userid", "password""), new StaticConfiguration("com.sun.security.auth.module.Krb5LoginModule"));
    lc.login();

    lc.logout();
}
catch (LoginException le)
{
    throw new ValidationException("Anmeldung fehlgeschlagen: " + le.getMessage(), le);
}
catch (Exception ex)
{
    throw new ValidationException("Anmeldung fehlgeschlagen: " + ex.getMessage(), ex);
}
```

Wir müssen bei unseren Windows-Anmeldung die Domaine (AD) voranstellen (adname.dom) und dann die userid. Beispiel oben im Quelltext adname.dom\\userid.
(Doppel Backslash sind nur wegen String)

Nur leider funktioniert das nicht. 
Wie kann ich die Domaine mitgeben wie wenn ich sie an der Windows-Anmeldung mitgebe. 


So wie oben gezeigt geht es nicht. 

Hat jemand eine Idee?

Besten Dank, grüße franzy


----------



## franzy (5. Mrz 2021)

ach so hier ist der Ursprungs Quelltext her für die Auth ohne Domainanteil im Benutzername. das klappt auch.


----------



## kneitzel (5. Mrz 2021)

Wenn Du die Domain mit angeben musst, dann könntest Du die @ Schreibweise ausprobieren: user@domain ist auch eine gültige Schreibweise.

Aber keine Ahnung, ob es etwas bringt. Wäre einfach mal ein Versuch wert. Ich selbst habe in Java noch nie gegen AD eine Anmeldung gemacht ...


----------



## Oneixee5 (5. Mrz 2021)

meiner Meinung nach muss das so aussehen:

```
/**
  * Get Active Directory domain controllers.
  *
  * Shell example: nslookup -type=SRV _ldap._tcp.dc._msdcs.mydomain.local
  *
  * @param domain
  *            Domain name (e.g. "mydomain.local")
  * @return Domain controllers (list may be empty)
  * @throws NamingException
  */
 private static Collection<InetSocketAddress> getDomainControllers(String domain) throws NamingException {
     final String typeSRV = "SRV";
     final String[] types = new String[] { typeSRV };
     DirContext ctx = new InitialDirContext();
     Attributes attributes = ctx.getAttributes("dns:/_ldap._tcp.dc._msdcs." + domain, types);
     if (attributes.get(typeSRV) == null) {
         return Collections.emptyList();
     }
     NamingEnumeration<?> e = attributes.get(typeSRV).getAll();
     TreeMap<Integer, InetSocketAddress> result = new TreeMap<>();
     while (e.hasMoreElements()) {
         String line = (String) e.nextElement();
         // The line is: priority weight port host
         String[] parts = line.split("\\s+");
         int prio = Integer.parseInt(parts[0]);
         int port = Integer.parseInt(parts[2]);
         String host = parts[3];
         result.put(prio, new InetSocketAddress(host, port));
     }
     return result.values();
 }
```


```
LoginContext lc;
String domainName, username, password = ...
// get domain controller for login
Collection<InetSocketAddress> result = getDomainControllers(domainName);
if (result.isEmpty()) {
    throw new ValidationException("No domain controllers found for domain " + domainName);
}
String loginServer = result.iterator().next().getHostString();
System.setProperty("java.security.krb5.realm", domainName.toUpperCase());
System.setProperty("java.security.krb5.kdc", loginServer);

 // perform login
lc = new LoginContext("", null, new StaticCallbackHandler(username, password),
        new StaticConfiguration("com.sun.security.auth.module.Krb5LoginModule"));
lc.login();

// logout (we want to check the password only)
lc.logout();
```
`domainName` und `username` musst du einfach vorher splitten entweder per `@` oder `\` wie oben beschrieben


----------



## franzy (8. Mrz 2021)

Guten Morgen,

ich hatte den Quelltext wie du ihn hier aufführst. Ich wollte ihn nur nicht komplett hier rein stellen, weil die getDomainControllers ja nur dazu da ist die Controller zu bekommen. In meinem Quelltext habe ich einen DC vorausgesetzt, daher meine Kürzungen.

Was meinst du mit: 


> domainName und username musst du einfach vorher splitten entweder per @ oder \ wie oben beschrieben



Das Problem ist nicht den Usernamen abzuschneiden. Nein an der Domaine wird sich so angemeldet, also muss ich doch auch hier den Usernamen so lassen. 

Gibt es keine Möglichkeit die Domaine beim LoginContext mitzugeben oder eben anders?

Grüße Franzy


----------



## Oneixee5 (8. Mrz 2021)

Bei mir funktioniert der Code so und es gibt hier im Landesnetz mehrere Domains. Allerdings beachte ich noch die Prioritäten, welche von der DNS-Anfrage zurückkommen, da es auch X DomainController gibt. Für die Anmeldung ist auch hier zwingend die Domain notwendig, sie ist aber niemals Teil des Usernamens sondern ein Feld im AD (OU=Domain Controllers,DC=*****,DC=de).


----------



## franzy (10. Mrz 2021)

Hallo,

also mit dem @ geht auch nicht.

@Oneixee5: Du versteht etwas falsch. Ich habe doch oben einen Screen von einer Windows Anmeldung. Unter Windows kann man sich, wie in dem Screen gezeigt, mit der Domain und Benutzernamen anmelden. Das sollte an jedem Windows System gehen, wenn man vor den Namen die Domaine stellt, so zumindest die Aussage meines Netzwerkadmins. Und genau das will ich jetzt hier auch ermöglichen.
Ich verstehe dich wahrscheinlich noch nicht korrekt.

Grüße Franzy


----------



## Oneixee5 (10. Mrz 2021)

Ja, ich verstehe das schon. Du musst den Usernamen einfach auftrennen in Domain und Name. Das ist alles.


----------



## franzy (11. Mrz 2021)

Hallo,

aber wo gebe ich dann die Domaine mit, damit die richtige Domaine genommen wird?

Grüße Franzy


----------



## mihe7 (13. Mrz 2021)

@franzy, aus Kommentar #4


Oneixee5 hat gesagt.:


> System.setProperty("java.security.krb5.realm", domainName.toUpperCase());


----------



## franzy (15. Mrz 2021)

Hallo zusammen,

durch den Hinweis von mihe7 habe ich gesehen wo mein Fehler lag, oder besser gesagt das Problem.
Ich erkläre vielleicht noch einmal was ich machen will.
Ich habe zwei Domainen und in beiden Domainen muss ich prüfen, ob der User vorhanden ist. Der kann nur in einem der Domainen vorhanden sein! Das stellt erst einmal so kein Problem dar. ein paar loops, fertig , so habe ich gedacht.

Mein Problem jedoch kommt durch folgende Anweisung zustande:

```
System.setProperty("java.security.krb5.realm", domainName.toUpperCase());
System.setProperty("java.security.krb5.kdc", loginServer);
```

Wenn sich der Doaminname während der Verarbeitung ändert dann wird in der falschen Domaine gesucht. Das Property wird nicht überschrieben mit dem "neuen" Domainname, deshalb findet er den User auch nicht.

Erst wenn ich denn Applikationsserver neu restarte funktioniert es. Das ist aber Quatsch, ich muss ja während der Laufzeit prüfen.

Gibt es da eine andere Möglichkeit? Wie werden die denn im weiteren Verlauf verwendet? In der Klasse LoginContext finde ich kein getProperty in dem Kontext.

Grüße und danke an Alle!


----------



## mihe7 (15. Mrz 2021)

Reload Kerberos config in JAVA without restarting JVM
					

The following code is for authenticating to a windows AD server using Java+Kerberos and it works fine-  public class KerberosAuthenticator {   public static void main(String[] args) {     String




					stackoverflow.com


----------



## franzy (17. Mrz 2021)

Hallo,

mit sun.security.krb5.Config.refresh(); scheint es zu funktionieren.

Danke!


----------



## Programmer20 (25. Mrz 2021)

kneitzel hat gesagt.:


> Wenn Du die Domain mit angeben musst, dann könntest Du die @ Schreibweise ausprobieren: user@domain ist auch eine gültige Schreibweise.
> 
> Aber keine Ahnung, ob es etwas bringt. Wäre einfach mal ein Versuch wert. Ich selbst habe in Java noch nie gegen AD eine Anmeldung gemacht ...


Das hat bei mir damals geklappt!


----------

