You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
8.1 KiB
216 lines
8.1 KiB
package de.superx.servlet; |
|
|
|
import java.io.File; |
|
import java.io.FileInputStream; |
|
import java.io.IOException; |
|
import java.io.InputStream; |
|
import java.util.Date; |
|
import java.util.Properties; |
|
import java.util.logging.Level; |
|
import java.util.logging.Logger; |
|
|
|
import javax.naming.Context; |
|
import javax.naming.NamingEnumeration; |
|
import javax.naming.NamingException; |
|
import javax.naming.directory.DirContext; |
|
import javax.naming.directory.InitialDirContext; |
|
import javax.naming.directory.SearchControls; |
|
import javax.naming.directory.SearchResult; |
|
|
|
import de.memtext.util.StringUtils; |
|
|
|
/** |
|
* Prüft per LDAP ob ein eingegebenes Passwort korrekt ist Vorlage |
|
* https://stackoverflow.com/questions/2522770/how-to-check-user-password-in-ldap-whith-java-with-given-ldapcontext |
|
* |
|
* Versuch mit statischem Context in |
|
* git/edustore/Entwicklung/code_ablage/LdapPasswordChecker-with-static-Context.java |
|
* Da Performancevorteil aber nur 0,2 Sekunden wegen möglicher Folgeeffekte |
|
* nicht genutzt. |
|
* |
|
* @author MB 2/2021 |
|
* |
|
*/ |
|
public class LdapPasswordChecker { |
|
private static Properties props = new Properties(); |
|
private static String[] attributeFilter = new String[1]; |
|
private static boolean hasLdapServiceUserDN = false; |
|
private static boolean wasSetupTestOK = false; |
|
private static boolean isStandaloneTest = false; |
|
|
|
public static void main(String[] args) { |
|
isStandaloneTest = true; |
|
if (args.length != 3) { |
|
System.out.println("LdapPasswordChecker path_to_config_file username password"); |
|
System.exit(1); |
|
} |
|
|
|
try { |
|
setup(new File(args[0])); |
|
LdapPasswordChecker lpc=new LdapPasswordChecker(); |
|
lpc.isLdapPasswordOK(false, "default", args[1], args[2]); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} |
|
} |
|
|
|
public static void setup(File superxStandaloneLdapConfigFile) throws IOException { |
|
InputStream is = new FileInputStream(superxStandaloneLdapConfigFile); |
|
props.load(is); |
|
is.close(); |
|
checkProperty(superxStandaloneLdapConfigFile, "LdapUrl"); |
|
checkProperty(superxStandaloneLdapConfigFile, "LdapBase"); |
|
checkProperty(superxStandaloneLdapConfigFile, "LdapIdentifyingAttribute"); |
|
if (!StringUtils.isNullOrEmpty(props.getProperty("LdapServiceUserDN"))) { |
|
hasLdapServiceUserDN = true; |
|
System.out.println(" LDAP Passwortkontrolle ServiceUser "+props.getProperty("LdapServiceUserDN")+" aktiviert"); |
|
// momentan keine Prüfung ob LdapServiceUserPassword null oder Leerstring |
|
} |
|
// we don't need all attributes, just let it get the identifying one |
|
LdapPasswordChecker.attributeFilter[0] = props.getProperty("LdapIdentifyingAttribute"); |
|
|
|
// Verbindungstest wirft Exception bei Fehler |
|
boolean isJustSetupTest = true; |
|
String mandantenIDNichtRelevant = "default"; |
|
String beliebigerTestUser = "superx"; |
|
String testpassword = "not_relevant_just_testing_connection"; |
|
if (isStandaloneTest) { |
|
System.out.println("Starte Verbindungstest"); |
|
} |
|
new LdapPasswordChecker().isLdapPasswordOK(isJustSetupTest, mandantenIDNichtRelevant, beliebigerTestUser, |
|
testpassword); |
|
if (isStandaloneTest) { |
|
System.out.println(" Verbindungstest OK"); |
|
System.out.println(""); |
|
} |
|
wasSetupTestOK = true; |
|
} |
|
|
|
private static void checkProperty(File superxStandaloneLdapConfigFile, String name) throws IllegalStateException { |
|
if (StringUtils.isNullOrEmpty(props.getProperty(name))) |
|
throw new IllegalStateException( |
|
" Property \"" + name + "\" ist in Datei " + superxStandaloneLdapConfigFile + " nicht konfiguiert"); |
|
} |
|
|
|
/** |
|
* Prüft via LDAP ob ein Passwort OK ist |
|
* |
|
* @param isJustSetupTest - auf true, wenn nur intern für SetupTest genutzt |
|
* wird, sonst false! |
|
* @param mandantenID - für richtigen Logger |
|
* @param username |
|
* @param password |
|
* @return |
|
*/ |
|
public boolean isLdapPasswordOK(boolean isJustSetupTest, String mandantenID, String username, String password) { |
|
Date start = new Date(); |
|
if (props.size() == 0) |
|
throw new IllegalStateException( |
|
"LDAP Passwordchecker nicht konfiguiert, setup Methode muss vorher aufgerufen werden"); |
|
if (!isJustSetupTest && !wasSetupTestOK) |
|
throw new IllegalStateException("LDAP Setup für gesamten Server war nicht erfolgreich"); |
|
DirContext serviceCtx = null; |
|
try { |
|
serviceCtx = initContext(); |
|
if (isStandaloneTest) { |
|
System.out.println("Reine Kontrolle, ob User "+username+ " existiert"); |
|
} |
|
NamingEnumeration<SearchResult> searchResults = searchForUser(serviceCtx, username); |
|
if (!isJustSetupTest) { |
|
tryAuthentification(searchResults, username, password); |
|
} |
|
return true; |
|
|
|
} catch (Exception e) { |
|
if (e.getMessage() != null && e.getMessage().indexOf("Invalid Credentials") > -1) |
|
Logger.getLogger("superx_" + mandantenID).log(Level.INFO, |
|
" Authentifizierung via LDAP für User " + username + " fehlgeschlagen :" + e.toString()); |
|
if (e.getLocalizedMessage() != null && e.getLocalizedMessage().indexOf("Kein LDAP Eintrag für User") > -1) |
|
Logger.getLogger("superx_" + mandantenID).log(Level.INFO, |
|
" Kein LDAP User " + username + " gefunden :" + e.toString()); |
|
else |
|
e.printStackTrace(); |
|
} finally { |
|
if (serviceCtx != null) { |
|
try { |
|
serviceCtx.close(); |
|
} catch (NamingException e) { |
|
e.printStackTrace(); |
|
} |
|
|
|
} |
|
//System.out.println(new Date().getTime() - start.getTime()); |
|
} |
|
return false; |
|
} |
|
|
|
private NamingEnumeration<SearchResult> searchForUser(DirContext serviceCtx, String username) |
|
throws NamingException { |
|
SearchControls sc = new SearchControls(); |
|
sc.setReturningAttributes(attributeFilter); |
|
sc.setSearchScope(SearchControls.SUBTREE_SCOPE); |
|
|
|
// use a search filter to find only the user we want to authenticate |
|
String searchFilter = ""; |
|
if (props.getProperty("LdapSearchFilter")!=null) |
|
{ |
|
searchFilter=StringUtils.replace(props.getProperty("LdapSearchFilter"),"${0}", username ); |
|
} |
|
else |
|
{ |
|
searchFilter="(" + props.getProperty("LdapIdentifyingAttribute") + "=" + username + ")"; |
|
} |
|
//searchFilter="(&(uid="+username+")(mail=boyle@ldap.forumsys.com))"; |
|
|
|
return serviceCtx.search(props.getProperty("LdapBase"), searchFilter, sc); |
|
} |
|
|
|
/** |
|
* Versucht einen Verbindungsaufbau, falls Passwort falsch wird NamingException |
|
* mit "Invalid Credentials" geworfen |
|
* |
|
* @throws NamingException,IllegalStateException |
|
*/ |
|
private void tryAuthentification(NamingEnumeration<SearchResult> searchResults, String username, String password) |
|
throws NamingException { |
|
if (isStandaloneTest) { |
|
System.out.println("Versuche Authentifizierung"); |
|
} |
|
if (searchResults.hasMore()) { |
|
// get the users DN (distinguishedName) from the result |
|
SearchResult result = searchResults.next(); |
|
String distinguishedName = result.getNameInNamespace(); |
|
if (isStandaloneTest) { |
|
System.out.println(" User "+username +" gefunden - distingushedName(DN/nameInNamespace):"+distinguishedName); |
|
System.out.println(" versuche Authentifizierung für "+distinguishedName+" mit eingegebenen Passwort"); |
|
} |
|
// attempt another authentication, now with the user, throws exception if |
|
// problem |
|
Properties authEnv = new Properties(); |
|
authEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); |
|
authEnv.put(Context.PROVIDER_URL, props.getProperty("LdapUrl")); |
|
authEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); |
|
authEnv.put(Context.SECURITY_PRINCIPAL, distinguishedName); |
|
authEnv.put(Context.SECURITY_CREDENTIALS, password); |
|
new InitialDirContext(authEnv); |
|
if (isStandaloneTest) { |
|
System.out.println("Authentifizierung erfolgreich"); |
|
} |
|
} else { |
|
throw new IllegalStateException(" Kein gültiger LDAP Eintrag für User " + username + " gefunden"); |
|
} |
|
|
|
} |
|
|
|
private InitialDirContext initContext() throws NamingException { |
|
Properties serviceEnv = new Properties(); |
|
serviceEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); |
|
serviceEnv.put(Context.PROVIDER_URL, props.getProperty("LdapUrl")); |
|
serviceEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); |
|
if (hasLdapServiceUserDN) { |
|
serviceEnv.put(Context.SECURITY_PRINCIPAL, props.getProperty("LdapServiceUserDN")); |
|
serviceEnv.put(Context.SECURITY_CREDENTIALS, props.getProperty("LdapServiceUserPassword")); |
|
} |
|
return new InitialDirContext(serviceEnv); |
|
} |
|
}
|
|
|