Index: httpclient/pom.xml =================================================================== --- httpclient/pom.xml (revision 1517999) +++ httpclient/pom.xml (working copy) @@ -57,6 +57,16 @@ compile + net.java.dev.jna + jna + compile + + + net.java.dev.jna + jna-platform + compile + + junit junit test Index: httpclient/src/main/java/org/apache/http/impl/auth/CurrentUserCredentials.java =================================================================== --- httpclient/src/main/java/org/apache/http/impl/auth/CurrentUserCredentials.java (revision 0) +++ httpclient/src/main/java/org/apache/http/impl/auth/CurrentUserCredentials.java (working copy) @@ -0,0 +1,108 @@ +/* + * ==================================================================== + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.impl.auth; + +import java.io.Serializable; +import java.security.Principal; + +import org.apache.http.annotation.Immutable; +import org.apache.http.auth.Credentials; + +import com.sun.jna.platform.win32.Secur32Util; +import com.sun.jna.platform.win32.Secur32.EXTENDED_NAME_FORMAT; + + +/** + * Returns the current user credentials + */ +@Immutable +public class CurrentUserCredentials implements Credentials, Serializable, Principal { + + private static final long serialVersionUID = 4361166468529298169L; + + /** + * Get the SAM-compatible username of the currently logged-on user. + * + * @return String. + */ + public static String getCurrentUsername() { + return Secur32Util.getUserNameEx(EXTENDED_NAME_FORMAT.NameSamCompatible); + } + + /** + * The constructor with the fully qualified username and password combined + * string argument. + * + * @param usernamePassword the domain/username:password formed string + */ + private CurrentUserCredentials() { + + } + + // singleton + private static CurrentUserCredentials INSTANCE = null; + public static synchronized CurrentUserCredentials get() { + if(INSTANCE==null) { + INSTANCE = new CurrentUserCredentials(); + } + return INSTANCE; + } + + public Principal getUserPrincipal() { + return this; + } + + @Override + public int hashCode() { + return 245678; // always the same? + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o instanceof CurrentUserCredentials) { + return true; + } + return false; + } + + @Override + public String toString() { + return getCurrentUsername(); + } + + /** + * Returns an empty password + */ + public String getPassword() { + return ""; + } + + public String getName() { + return getCurrentUsername(); + } +} Property changes on: httpclient/src/main/java/org/apache/http/impl/auth/CurrentUserCredentials.java ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNTLMSchemeFactory.java =================================================================== --- httpclient/src/main/java/org/apache/http/impl/auth/WindowsNTLMSchemeFactory.java (revision 0) +++ httpclient/src/main/java/org/apache/http/impl/auth/WindowsNTLMSchemeFactory.java (working copy) @@ -0,0 +1,54 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.impl.auth; + +import org.apache.http.annotation.Immutable; +import org.apache.http.auth.*; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; + +/** + * {@link AuthSchemeProvider} implementation that creates and initializes + * {@link WindowsNegotiateScheme} using JNA to implement NTLM + * + * @since 4.3 + */ +@Immutable +@SuppressWarnings("deprecation") +public class WindowsNTLMSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider { + + public static final String SCHEME = "NTLM"; + + public AuthScheme newInstance(final HttpParams params) { + return new WindowsNegotiateScheme(SCHEME); + } + + public AuthScheme create(final HttpContext context) { + return new WindowsNegotiateScheme(SCHEME); + } +} Property changes on: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNTLMSchemeFactory.java ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateScheme.java =================================================================== --- httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateScheme.java (revision 0) +++ httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateScheme.java (working copy) @@ -0,0 +1,252 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.http.impl.auth; + +import java.util.Locale; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.Header; +import org.apache.http.HttpRequest; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.auth.AUTH; +import org.apache.http.auth.AuthenticationException; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.InvalidCredentialsException; +import org.apache.http.auth.MalformedChallengeException; +import org.apache.http.impl.auth.AuthSchemeBase; +import org.apache.http.message.BufferedHeader; +import org.apache.http.util.CharArrayBuffer; + + +import com.sun.jna.platform.win32.Secur32; +import com.sun.jna.platform.win32.Sspi.CredHandle; +import com.sun.jna.platform.win32.Sspi.CtxtHandle; +import com.sun.jna.platform.win32.Sspi.SecBufferDesc; +import com.sun.jna.platform.win32.Sspi.TimeStamp; +import com.sun.jna.platform.win32.Sspi; +import com.sun.jna.platform.win32.Win32Exception; +import com.sun.jna.platform.win32.WinError; +import com.sun.jna.ptr.IntByReference; + + +/** + * Use JNA to implement Negotiate & NTLM + * + * This will delegate negotiation to the windows machine. + */ +@NotThreadSafe +public class WindowsNegotiateScheme extends AuthSchemeBase { + + public static boolean isAvaliable() { + String os = System.getProperty("os.name").toLowerCase(Locale.ROOT); + if(os.indexOf("windows")>=0) { + try { + return Sspi.MAX_TOKEN_SIZE > 0; + } + catch(Throwable t) { // Likely ClassNotFound + return false; + } + } + return false; + } + + // NTLM or Negotiate + private final String scheme; + + private CredHandle clientCred = null; + private CtxtHandle context = null; + private boolean continueNeeded = true; + private String challenge; + + public WindowsNegotiateScheme(String scheme) { + super(); + + if(scheme==null) { + scheme = WindowsNegotiateSchemeFactory.SCHEME; + } + this.scheme = scheme; + this.challenge = null; + } + + public void dispose() { + if (clientCred != null && !clientCred.isNull()) { + int rc = Secur32.INSTANCE.FreeCredentialsHandle(clientCred); + if (WinError.SEC_E_OK != rc) { + throw new Win32Exception(rc); + } + } + if (context != null && !context.isNull()) { + int rc = Secur32.INSTANCE.DeleteSecurityContext(context); + if (WinError.SEC_E_OK != rc) { + throw new Win32Exception(rc); + } + } + continueNeeded = true; // waiting + clientCred = null; + context = null; + } + + @Override + public void finalize() { + dispose(); + } + + public String getSchemeName() { + return scheme; + } + + // String parameters not supported + public String getParameter(final String name) { + return null; + } + + // NTLM/Negotiate do not support authentication realms + public String getRealm() { + return null; + } + + public boolean isConnectionBased() { + return true; + } + + + @Override + protected void parseChallenge( + final CharArrayBuffer buffer, + final int beginIndex, + final int endIndex) throws MalformedChallengeException { + this.challenge = buffer.substringTrimmed(beginIndex, endIndex); + + if (this.challenge.length() == 0) { + if(clientCred==null) { + // OK + } + else { + if(continueNeeded) { + throw new RuntimeException("Unexpected token"); + } + dispose(); + } + } + } + + public Header authenticate( + final Credentials credentials, + final HttpRequest request) throws AuthenticationException { + + String response = null; + if(clientCred==null) { + // ?? We don't use the credentials, should we allow anything? + if(!(credentials instanceof CurrentUserCredentials)) { + throw new InvalidCredentialsException( + "Credentials cannot be used for "+getSchemeName()+" authentication: " + + credentials.getClass().getName()); + } + + // client credentials handle + try { + String username = CurrentUserCredentials.getCurrentUsername(); + TimeStamp lifetime = new TimeStamp(); + + clientCred = new CredHandle(); + int rc = Secur32.INSTANCE.AcquireCredentialsHandle(username, + scheme, Sspi.SECPKG_CRED_OUTBOUND, null, null, null, null, + clientCred, lifetime); + + if (WinError.SEC_E_OK != rc) { + throw new Win32Exception(rc); + } + + response = getToken(null, null,username); + } + catch(Throwable t) { + dispose(); + throw new AuthenticationException("Authentication Failed", t); + } + } + else if(this.challenge==null || this.challenge.length()==0){ + dispose(); + throw new AuthenticationException("Authentication Failed"); + } + else { + try { + byte[] continueTokenBytes = Base64.decodeBase64(this.challenge); + SecBufferDesc continueTokenBuffer = new SecBufferDesc( + Sspi.SECBUFFER_TOKEN, continueTokenBytes); + response = getToken(context, continueTokenBuffer, "localhost"); + } + catch(Throwable t) { + dispose(); + throw new AuthenticationException("Authentication Failed", t); + } + } + + final CharArrayBuffer buffer = new CharArrayBuffer(scheme.length()+30); + if (isProxy()) { + buffer.append(AUTH.PROXY_AUTH_RESP); + } else { + buffer.append(AUTH.WWW_AUTH_RESP); + } + buffer.append(": "); + buffer.append(scheme); // NTLM or Negotiate + buffer.append(" "); + buffer.append(response); + return new BufferedHeader(buffer); + } + + /** + * @see http://msdn.microsoft.com/en-us/library/windows/desktop/aa375506(v=vs.85).aspx + */ + private String getToken(CtxtHandle continueCtx, SecBufferDesc continueToken, String targetName) { + IntByReference attr = new IntByReference(); + SecBufferDesc token = new SecBufferDesc( + Sspi.SECBUFFER_TOKEN, Sspi.MAX_TOKEN_SIZE); + + context = new CtxtHandle(); + int rc = Secur32.INSTANCE.InitializeSecurityContext(clientCred, + continueCtx, targetName, Sspi.ISC_REQ_CONNECTION, 0, + Sspi.SECURITY_NATIVE_DREP, continueToken, 0, context, token, + attr, null); + switch (rc) { + case WinError.SEC_I_CONTINUE_NEEDED: + continueNeeded = true; + break; + case WinError.SEC_E_OK: + dispose(); // Don't keep the context + continueNeeded = false; + break; + default: + dispose(); + throw new Win32Exception(rc); + } + return Base64.encodeBase64String(token.getBytes()); + } + + public boolean isComplete() { + return !continueNeeded; + } +} Property changes on: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateScheme.java ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateSchemeFactory.java =================================================================== --- httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateSchemeFactory.java (revision 0) +++ httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateSchemeFactory.java (working copy) @@ -0,0 +1,54 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.impl.auth; + +import org.apache.http.annotation.Immutable; +import org.apache.http.auth.*; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; + +/** + * {@link AuthSchemeProvider} implementation that creates and initializes + * {@link WindowsNegotiateScheme} using JNA to Negotiate credentials + * + * @since 4.3 + */ +@Immutable +@SuppressWarnings("deprecation") +public class WindowsNegotiateSchemeFactory implements AuthSchemeFactory, AuthSchemeProvider { + + public static final String SCHEME = "Negotiate"; + + public AuthScheme newInstance(final HttpParams params) { + return new WindowsNegotiateScheme(SCHEME); + } + + public AuthScheme create(final HttpContext context) { + return new WindowsNegotiateScheme(SCHEME); + } +} Property changes on: httpclient/src/main/java/org/apache/http/impl/auth/WindowsNegotiateSchemeFactory.java ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: httpclient/src/test/java/org/apache/http/impl/auth/TestWindowsNegotiateScheme.java =================================================================== --- httpclient/src/test/java/org/apache/http/impl/auth/TestWindowsNegotiateScheme.java (revision 0) +++ httpclient/src/test/java/org/apache/http/impl/auth/TestWindowsNegotiateScheme.java (working copy) @@ -0,0 +1,87 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.http.impl.auth; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.auth.AuthSchemeRegistry; +import org.apache.http.auth.AuthScope; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.util.EntityUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + * This class needs obvious help -- it hits a running server + */ +public class TestWindowsNegotiateScheme { + + @Test + public void testAuthenticationRequested() throws Exception { + if(!WindowsNegotiateScheme.isAvaliable()) { + // skip the test + return; + } + + AuthSchemeRegistry authSchemeRegistry = new AuthSchemeRegistry(); + authSchemeRegistry.register(WindowsNegotiateSchemeFactory.SCHEME, new WindowsNegotiateSchemeFactory()); + authSchemeRegistry.register(WindowsNTLMSchemeFactory.SCHEME, new WindowsNTLMSchemeFactory()); + + DefaultHttpClient httpclient = new DefaultHttpClient(); + httpclient.setAuthSchemes(authSchemeRegistry); + + try { + httpclient.getCredentialsProvider().setCredentials( + AuthScope.ANY, + CurrentUserCredentials.get()); + + HttpGet httpget = new HttpGet("http://localhost:8888/account/login"); + + System.out.println("executing request" + httpget.getRequestLine()); + HttpResponse response = httpclient.execute(httpget); + HttpEntity entity = response.getEntity(); + + System.out.println("----------------------------------------"); + System.out.println(response.getStatusLine()); + if (entity != null) { + System.out.println("Response content length: " + entity.getContentLength()); + } + String body = EntityUtils.toString(entity); + System.out.println("----------------------------------------"); + System.out.println(body); + + Assert.assertTrue(body.indexOf(CurrentUserCredentials.getCurrentUsername())>0); + } + finally { + // When HttpClient instance is no longer needed, + // shut down the connection manager to ensure + // immediate deallocation of all system resources + httpclient.getConnectionManager().shutdown(); + } + } +} Property changes on: httpclient/src/test/java/org/apache/http/impl/auth/TestWindowsNegotiateScheme.java ___________________________________________________________________ Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: pom.xml =================================================================== --- pom.xml (revision 1517999) +++ pom.xml (working copy) @@ -74,6 +74,7 @@ 4.9 2.5.2 1.8.5 + 4.0.0 1 4.2 @@ -123,6 +124,16 @@ ${memcached.version} + net.java.dev.jna + jna + ${jna.version} + + + net.java.dev.jna + jna-platform + ${jna.version} + + junit junit ${junit.version}