AW: [jcifs] Re: Websphere+SSO+NTLM
Waldheim, Frank
F.Waldheim at ing-diba.de
Tue Dec 12 08:26:04 GMT 2006
> -----Ursprüngliche Nachricht-----
> Von: jcifs-bounces+f.waldheim=ing-diba.de at lists.samba.org
> [mailto:jcifs-bounces+f.waldheim=ing-diba.de at lists.samba.org]
> Im Auftrag von altiuser
> Gesendet: Mittwoch, 6. Dezember 2006 16:12
> An: jcifs at lists.samba.org
> Betreff: [jcifs] Re: Websphere+SSO+NTLM
>
> I am stranded, any one out there who can provide some leads, please?
>
>
>
hi there,
there is a feature in websphere where you can assert credentials
to your container.
the technique utilized there is called TAI (Trusted Association Interceptor).
i do have a working prototype of a tai for websphere 6.0.x
please read:
http://www-128.ibm.com/developerworks/websphere/techjournal/0508_benantar/0508_benantar.html
to find out how to install such a TAI and what preconditions must be met by your surrounding
application.
my version is attached.
~fw
Diese E-Mail enthaelt vertrauliche und/oder rechtlich geschuetzte
Informationen. Wenn Sie nicht der richtige Adressat sind oder diese
E-Mail irrtuemlich erhalten haben, informieren Sie bitte sofort den
Absender und vernichten Sie diese Mail. Das unerlaubte Kopieren sowie
die unbefugte Weitergabe dieser Mail ist nicht gestattet.
This e-mail may contain confidential and/or privileged information.
If you are not the intended recipient (or have received this e-mail
in error) please notify the sender immediately and destroy this e-
mail.
Any unauthorized copying, disclosure or distribution of the material
in
this e-mail is strictly forbidden.
-------------- next part --------------
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Properties;
import javax.security.auth.Subject;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import jcifs.Config;
import jcifs.UniAddress;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.smb.NtlmChallenge;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbAuthException;
import jcifs.smb.SmbException;
import jcifs.smb.SmbSession;
import jcifs.smb.SmbTransport;
import jcifs.util.Base64;
import com.ibm.websphere.security.WebTrustAssociationException;
import com.ibm.websphere.security.WebTrustAssociationFailedException;
import com.ibm.wsspi.security.tai.TAIResult;
import com.ibm.wsspi.security.tai.TrustAssociationInterceptor;
import com.ing.diba.AuthData;
/**
* the NTLM TAI Prototype
*
* CCCs:
* - XXX: enable usefull logging?
* - XXX: make it configureable? especially isTargetInterceptor Logic
*
*
*/
public class NtlmTai implements TrustAssociationInterceptor {
private static final String NTLMCHALLENGE = "ntlmchallenge";
private static final String NTLMAUTH = "ntlmauth";
/**
* configure the jcifs lib according to the properties used in
* production by callimero
*/
public NtlmTai() {
super();
System.out.println("new NtmlTai");
// try to configure the JcifLib
Config.setProperty("jcifs.smb.client.domain", "DOMDIBACORP");
Config.setProperty("jcifs.netbios.wins", "gf01swdc01,gh0aswdc02,gn01swdc01,gf02swdc01,gn01swdc02,gh0bswdc02,gn02swdc02,gf0bswdc02");
Config.setProperty("jcifs.http.loadBalance", "true");
Config.setProperty("jcifs.util.loglevel", "9");
Config.setProperty("jcifs.smb.lmCompatibility", "3");
/* Config.setProperty("jcifs.smb.client.username", "userCallimero");
Config.setProperty("jcifs.smb.client.password", "Calli864ro");
*/ Config.setProperty("jcifs.smb.client.ssnLimit", "1");
Config.setProperty("jcifs.smb.client.soTimeout", "3500");
}
/*
* only intercept for requests containing: "/optical" and "ntlm.ac" int the request uri
* XXX - this really should be more clever
*/
public boolean isTargetInterceptor(HttpServletRequest req) throws WebTrustAssociationException {
// we only work for windows-ntlm users using optical
if (req.getContextPath().indexOf("optical") != -1 && req.getRequestURI().endsWith("ntlm.ac")) {
System.out.println("NtlmTai will handle request");
return true;
} else {
System.out.println("NtlmTai will NOT handle request");
return false;
}
}
/**
* just a convenience method - although actually illegal as it flushes the
* response (by forwarding) and therefore leaves the TAIREsult with a
* IllegalStateException (as also documented in the servletspec)
* XXX - please find a more sophisticated control flow logic here
*/
private TAIResult gotoError(Exception sae, HttpServletRequest req, HttpServletResponse resp) throws WebTrustAssociationFailedException {
try {
req.setAttribute("error", sae);
sae.printStackTrace();
RequestDispatcher dispatcher = req.getRequestDispatcher("/error.jsp");
dispatcher.forward(req, resp);
return TAIResult.create(HttpServletResponse.SC_UNAUTHORIZED);
} catch (Exception e) {
e.printStackTrace();
throw new WebTrustAssociationFailedException(e.getMessage());
}
}
/*
* XXX: early out (after the selected phase)
* XXX: the documentation suggests HTTPServletResponse.SC_CONTINUE
* as a TAIResult but the RFC for NTLM wants 401 (so i just dont know)
* */
public TAIResult negotiateValidateandEstablishTrust(HttpServletRequest req, HttpServletResponse resp) throws WebTrustAssociationFailedException {
// Phase 1:
// if
// - no 'Authorization' header is avail or
// - we have such a header but it is not our beer or
// - we don't have a session yet
// ===> we have to tell the client to come back (and create a session for him).
// check whether we are in the first phase
String msg = req.getHeader("Authorization");
// XXX bitte beachten: hier wird kein 'false'uebergeben - es wird also eine neue Session angelegt.
HttpSession session = req.getSession();
if (session == null || msg == null || (msg != null && !msg.startsWith("NTLM"))) {
resp.setHeader("WWW-Authenticate", "NTLM");
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.setContentLength(0);
if (session == null) {
session = req.getSession(true);
System.out.println("phase1: created session " + session.getId());
} else {
System.out.println("phase1: using session " + session.getId());
}
System.out.println("phase1: returning 401 - please come back");
return TAIResult.create(HttpServletResponse.SC_UNAUTHORIZED);
}
// Phase 2:
// if we get Type1:
// - get a challenge
// - store it in the session
// - XXX - remove challenge from session.
// ==> create Type2 and send it back
byte[] src = Base64.decode(msg.substring(5));
try {
if (src[8] == 1) {
Type1Message type1 = new Type1Message(src);
System.out.println("phase2: trying to get challenge");
NtlmChallenge challenge = SmbSession.getChallengeForDomain();
System.out.println("phase2: got challenge: " + challenge + " from DC " + challenge.dc);
// note we set it here - recover it later and then remove it.
session.setAttribute(NTLMCHALLENGE, challenge);
Type2Message type2 = new Type2Message(type1, challenge.challenge, null);
msg = Base64.encode(type2.toByteArray());
resp.setHeader("WWW-Authenticate", "NTLM " + msg);
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
resp.setContentLength(0);
System.out.println("phase2: returning 401 - please respond to challenge");
return TAIResult.create(HttpServletResponse.SC_UNAUTHORIZED);
}
// leave the exceptions as they are during developement
// XXX - collapse exceptions as they are all in no way recoverable
} catch (SmbException sae) {
return gotoError(sae, req, resp);
} catch (UnknownHostException sae) {
return gotoError(sae, req, resp);
} catch (IOException sae) {
return gotoError(sae, req, resp);
}
// Phase 3:
// if we get a Type3
// - get challenge from session
// - get some info from msg
// - create NtlmPasswordAuthentication
// => authenticate user with the above
try {
if (src[8] == 3) {
Type3Message type3 = new Type3Message(src);
// XXX - pls understand this
byte[] lmResponse = type3.getLMResponse();
if (lmResponse == null) {
lmResponse = new byte[0];
}
byte[] ntResponse = type3.getNTResponse();
if (ntResponse == null) {
ntResponse = new byte[0];
}
NtlmChallenge challenge = (NtlmChallenge) session.getAttribute(NTLMCHALLENGE);
if (challenge != null) {
System.out.println("phase3: recovered challenge " + challenge + " with DC " + challenge.dc);
} else {
System.out.println("phase3: could not find a challenge in the session - bouncing out");
// should not happen - but doing the bounce out nevertheless as we really want a session here
// XXX - bouncing out.
}
NtlmPasswordAuthentication ntlm = new NtlmPasswordAuthentication(type3.getDomain(), type3.getUser(), challenge.challenge, lmResponse,
ntResponse);
System.out.println("phase3: got ntlm token " + ntlm);
// important note: please use the DC which created the challenge
// to avoid "Illegal access to memory"
UniAddress dc = challenge.dc;
System.out.println("phase3: trying to login... (DC = '" + dc + "')");
// if we have no exception we suceeded - return 200 - else. start again.
try {
SmbSession.logon(dc,challenge.localPort, ntlm );
System.out.println("phase3: successfully authenticated user " + ntlm.getUsername());
// now do the logoff which closes the actual connection
// XXX - just for the optical test thing - remove it pls
session.setAttribute(NTLMAUTH, ntlm);
Subject subject = AuthData.createSubject(ntlm.getUsername(), ntlm.getName(), ntlm.getPassword());
// ok, our subject has a principal with the same name as ntlm.getName which is returned as a
// principal-string here...
return TAIResult.create(HttpServletResponse.SC_OK, ntlm.getName(), subject);
} catch (SmbAuthException sae) {
System.out.println("phase3: Unable to authenticate user, got SmbAuthException: " + ntlm.getName() + ": 0x"
+ jcifs.util.Hexdump.toHexString(sae.getNtStatus(), 8) + ": " + sae);
return gotoError(sae, req, resp);
}
}
// leave the exceptions as they are during developement
// XXX - collapse exceptions as they are all in no way recoverable
} catch (SmbException sae) {
return gotoError(sae, req, resp);
} catch (UnknownHostException sae) {
return gotoError(sae, req, resp);
} catch (IOException sae) {
return gotoError(sae, req, resp);
}
System.out.println("FATAL: surprinsingly reached the end of the wurst - returning error");
return gotoError(new WebTrustAssociationFailedException(), req, resp);
}
/*
* XXX - we could use it if we want to be configured via WAS custom Properties
*/
public int initialize(Properties arg0) throws WebTrustAssociationFailedException {
return 0;
}
/*
* only for the container
*/
public String getVersion() {
return "1.0";
}
/*
* i dunno
*/
public String getType() {
return this.getClass().getName();
}
/*
* here we may have to really get rid of all the MS-stuff
* XXX - please do usefull things here
*/
public void cleanup() {
}
}
More information about the jcifs
mailing list