niedenzu

Hints and tricks for developers

Martins Amazon Wunschliste

Browser Quirk – Deselect Radiobuttons 22. September 2010

Wir haben 2 Gruppen von Radiobuttons.
Wenn die erste Gruppe auf Nein gestellt ist, so muss die zweite Gruppe deselectiert werden. Hierzu gibt es gleich mehrer Dinge zu beachten. Da sich der IE und der FF in diesem Punkt voneinander unterschiedlich verhalten

  1. Die Buttons (Gruppe 1) benötigen unbeding onclick=”this.blur()” . Damit der Internetexplorer auf die Veränderung reagiert.
  2. Fehlerhafte indexierung der Buttons im IE.

Definition der steuernden Buttons.

<input type="radio" onclick="this.blur()"
onchange="de_wwag_alma_anliegen_versicherungsfallchanged(this.value)"
value="true"
name="editForm:versicherungsfallJaNeinRadio">

<input type="radio" onclick="this.blur()"
onchange="de_wwag_alma_anliegen_versicherungsfallchanged(this.value)"
value="false"
name=":editForm:versicherungsfallJaNeinRadio" >

Deselektieren der abhängigen Buttons.

document.getElementsByName("view<portlet:namespace/>:editForm:versicherungsfallAltNeuRadio")[0].checked = false;
//This is a Browser Quirk - we only have 2 option
//In FF the indexes are 0 and 1
//In IE 0 and 2
document.getElementsByName("editForm:versicherungsfallAltNeuRadio")[0].checked = false;
document.getElementsByName("editForm:versicherungsfallAltNeuRadio")[1].checked = false;
document.getElementsByName("editForm:versicherungsfallAltNeuRadio")[2].checked = false;
No Comments on Browser Quirk – Deselect Radiobuttons
Categories: Uncategorized

Java JNDI ADS rekursive Gruppen eines Users 15. September 2010

Bei der Abfrage der Gruppen eines Users gibt es ein paar Fallstricke die zu überwinden sind. Der Nun folgende Sourcecode hat diese gelöst.Hier kann kann man somit “nachschauen” wie das Problem zu lösen ist.
Mit dem hier folgenden Know-How sollte die Anbindung einer Java-Anwendung an ein Active Directory relativ einfach zu implentieren sein.

Außerdem folgen nun einige Tips.

1. Verwenden Sie nicht den Server-name des ADS Servers, sondern lassen sie das Directory den besten Server auswählen. Nicht: myserver.mydomain.de sondern mydomain.de verwedenden. Sie werden dann automatisch mit dem am schnellsten anwortenden Server verbunden. Wenn sie eine Liste aller ADS-Server ihrere domain wollen, so hilft eine nslookup mydomain.de

2. Sie dürfen nicht anonym auf das ADS zugreifen. Sie benötigen also einen User der auf das Directory mindestens Lese-Berechtigung hat.

3. Die User-ID muss voll qualifiziert angegeben werden (mit Domain-Namen). Hier bitte die Schreibweise beachten: Nicht myuser@mydomain.de sondern mydomain\myuser .

4. ADS Administratoren verschachteln die Berechtigungen für User gerne. Dass heißt eine einfache Zuordnung von Usern zu den Gruppen ist nicht zulässig. Bei jeder angegebenen Gruppe muss überprüft werden, ob diese wiederum weitere Untergruppen beinhaltet.
Der rekursive Aufruf wurde hier elegant gelöst.

5. Eine häufige Fehlerquelle ist die Groß und Kleinschreibung. Es macht Sinn die die Mitgliedschaft einer Gruppe in uppercase zu vergleichen.

package de.nikem.ads;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Map.Entry;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class ListGroupsOfUserRecursiv {
public static void main(String args[]) {
ListGroupsOfUserRecursiv prog = new ListGroupsOfUserRecursiv();
prog.getGroupNames();
}

private void getGroupNames() {
InitialDirContext ctx;

String serverName = "mydomain.de";

String provider_url = "ldap://" + serverName + ":389";

String ldapuser = "mydomain\myuserid"; //technical id to connect to server
String ldappasswd = "mypwd";

String username = "useridofuser"; //the name is not case-sensitive

// Specify the Base for the search
String searchBase = "dc=mydomain,dc=de";

Hashtable<String,String> hashtable = new Hashtable<String,String>();
hashtable.put("java.naming.factory.initial",
"com.sun.jndi.ldap.LdapCtxFactory");
hashtable.put("java.naming.provider.url", provider_url);
hashtable.put("java.naming.ldap.version", "3");
hashtable.put("java.naming.security.authentication", "simple");
hashtable.put("java.naming.security.principal", ldapuser);
hashtable.put("java.naming.security.credentials", ldappasswd);

HashMap<String, String> groupMap = new HashMap<String, String>();
try {
ctx = new InitialDirContext(hashtable);
//System.out.println("Authentification O.K. gefunden... weiter geht'z...");
// Create the initial directory context
// LdapContext ctx = new InitialLdapContext(env,null);

// Create the search controls
SearchControls searchCtls = new SearchControls();

// Specify the search scope
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);

// specify the LDAP search filter
String searchFilter = "(&(objectClass=user)(cn="+username+"))";



// initialize counter to total the group members
int totalResults = 0;

// Specify the attributes to return
String returnedAtts[] = { "memberOf" };
searchCtls.setReturningAttributes(returnedAtts);

// Search for objects using the filter
NamingEnumeration answer = ctx.search(searchBase, searchFilter,
searchCtls);

// Loop through the search results
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult) answer.next();

//System.out.println(">>>" + sr.getName());

Attributes attrs = sr.getAttributes();
if (attrs != null) {

try {
for (NamingEnumeration<?> ae = attrs.getAll(); ae
.hasMore();) {
Attribute attr = (Attribute) ae.next();
//System.out.println("Attribute: " + attr.getID());
for (NamingEnumeration<?> e = attr.getAll(); e
.hasMore(); totalResults++) {

Object object = e.next();
// System.out.println(" " + totalResults + ". "
// + e.next());
String cn = object.toString().toUpperCase();
cn = cn.substring(0, cn.indexOf(","));
groupMap.put(cn, cn.substring(3, cn.length()));
}
}
} catch (NamingException e) {
System.err.println("Problem listing membership: " + e);
}
}
}

System.out.println("Direct groups:" +groupMap .size());

Map<String, String> newGroups = new HashMap<String, String>(
groupMap);
while (!newGroups.isEmpty()) {
Map<String, String> newThisRound = new HashMap<String, String>();
for (Entry<String, String> group : newGroups.entrySet()) {
String returnedAtts2[] = { "memberOf" };
searchCtls.setReturningAttributes(returnedAtts2);
searchFilter = "(&(objectClass=group)(" + group.getKey()
+ "))";
//System.out.println("Perform a nested group search with filter:"+ searchFilter);
NamingEnumeration<SearchResult> results = ctx.search(
searchBase, searchFilter, searchCtls);

try {
while (results.hasMore()) {
SearchResult result = results.next();
Attributes attrs = result.getAttributes();
if (attrs == null)
continue;
try {
String memberOf = getAttributeValue("memberOf",
attrs);
if (memberOf!=null) {
//System.out.println("memberOf:" + memberOf);
memberOf = memberOf.substring(0, memberOf.indexOf(",")).toUpperCase();
newThisRound.put(memberOf, memberOf.substring(3, memberOf.length()));
groupMap.put(memberOf, memberOf.substring(3, memberOf.length()));
}
} catch (NamingException e) {
System.err
.println("Problem listing membership: "
+ e);
}
}
} catch (PartialResultException ex) {

// nothing to do
}

}

newGroups = newThisRound;

}

System.out.println("Total groups: " + groupMap.size());

for (String groupName : groupMap.values()) {
System.out.println(groupName);
}
ctx.close();

}

catch (NamingException e) {
System.err.println("Problem searching directory: " + e);
}
}


private String getAttributeValue(String attrId, Attributes attrs)
throws NamingException {


if (attrId == null || attrs == null)
return null;

Attribute attr = attrs.get(attrId);
if (attr == null)
return (null);
Object value = attr.get();
if (value == null)
return (null);
String valueString = null;
if (value instanceof byte[])
valueString = new String((byte[]) value);
else
valueString = value.toString();

return valueString;
}

}

No Comments on Java JNDI ADS rekursive Gruppen eines Users
Categories: Uncategorized

Tomcat Authentication: Wie zeige ich den Grund für einen Authentifizierungsfehler an? 9. September 2010

Im Tomcat bietet es sich an, die J2EE Authentifizierung für geschützte Resourcen zu verwenden. Das Verfahren ist recht simpel einzurichten und wird auf vielen Seiten im Internet erklärt, z.B. hier.

Diese Einfache Methode der Authentifizierung leitet den User auf eine Login-Seite, falls er eine geschützte Resource aufrufen möchte, aber noch nicht angemeldet ist. Auf dieser Login-Seite wird ein Formular angezeigt, in das er Username und Passwort eingeben muss.

Schlägt die Authentifizierung aus irgend einem Grund fehl, wird der User auf die in der web.xml eingestellte Error-Seite weitergeleitet. In den meisten Anwendungen ist die Error-Seite die Login-Seite mit einem Hinweistext, dass die Authentifizierung nicht möglich war. Manchmal wird noch ein Link angeboten, über den der User sein Passwort zurücksetzen kann.

Bsp:

Das Problem ist jedoch, dass es auch andere Gründe für eine fehlgeschlagene Anmeldung geben kann, außer dass Username oder Passwort falsch eingegeben wurden:

  • Passwort ist abgelaufen.
  • Passwort wurde zu oft falsch eingegeben.
  • Konto wurde wegen Inaktivität gesperrt.
  • u.s.w.

Diese Informationen können dem User jedoch bei Verwendung der Standard-Authentifizierung nicht angezeigt werden.

Abhilfe schafft hier die Implementierung eines eigenen Valves zur Form-Authentifizierung. Die Klasse muss von org.apache.catalina.authenticator.FormAuthenticator abgeleitet werden (ganz richtig, das ist eine Tomcat-spezifische Klasse!). In dieser Klasse wird die Methode forwardToErrorPage() überschrieben. Die Methode wird vom Tomcat aufgerufen, nachdem die Authentifizierung fehlschlug und der User zur Error-Seite geleitet wird.

Eine Beispiel-Implementierung:


public class CustomFormAuthenticator extends FormAuthenticator {

@Override
protected void forwardToErrorPage(Request request, Response response,
LoginConfig config) throws IOException {
Integer errorReason = checkOutErrorReason();

request.setAttribute("loginErrorReason", errorReason);
super.forwardToErrorPage(request, response, config);
}

protected void checkOutErrorReason() {
//TODO hier die Ermittlung der Ursache für die
// abgelehnte Authentifizierung implementieren
return null;
}

}

In diesem Beispiel wird ein Request-Parameter gesetzt (loginErrorReason), der dann in der Error-Page ausgewertet werden kann.
Bsp.:


Integer errorReason = (Integer) request.getAttribute("loginErrorReason");

Wichtig ist, dass der CustomFormAuthenticator in einem jar im Tomcat/lib-Verzeichnis deployt wird, damit der Tomcat die Klasse findet.

Das Valve muss dann dem Tomcat noch in der Konfiguration im Context der Web-Anwendung (in server.xml) mitgeteilt werden:


...
<Context docBase="myapp" path="" reloadable="true">
<Valve className="custom.auth.CustomFormAuthenticator" />
</Context>
...

Eine andere Möglichkeit der Konfiguration besteht in der Web-Anwendung in der Datei META-INF/context.xml:


<Context>
<Valve className="custom.auth.CustomFormAuthenticator" />
</Context>
No Comments on Tomcat Authentication: Wie zeige ich den Grund für einen Authentifizierungsfehler an?
Categories: Java Tomcat
Martin Rocks