jcifs を Apache axis とうまく連携させるにはどうすればよいですか
質問
Apache Axis 1.4 を、NTLM 認証を使用して操作へのアクセスを制限する Web サービスに接続する必要があります。NTLM ハンドシェイクの処理には Samba Jcifs を使用する予定です。
見つけました
http://hc.apache.org/httpcomponents-client/ntlm.html
これにより、HttpClient 4.0 と jcifs を接続する方法についての素晴らしい指示が得られます。
問題は、Axis が Http Client 3.0 を使用したいのですが、2 つの API が大きく異なっているように見えることです。
考えられる可能性は2つあります
- HttpClient 4 にプラグインできる Axis のオブジェクトを作成します。
- HttpClient 3.0 を Samba Jcifs に接続する方法を考えてください。
1番。わずかなように見えますが、可能性があります。これを行う方法を説明した励ましのメッセージは Web 上で見つかりません。
私の質問は次のとおりです。誰かが samba jcifs を HttpClient 3.0 に接続することに成功しましたか?HttpClient 4 で動作する Axis HttpSender オブジェクトを既に作成した人はいますか?
私が検討したことのない、より良い代替手段はあるのでしょうか?
解決
最後にこれに対する解決策を持っています。
問題
Apache Axisのは、独自のNTLMの実装を提供し、ApacheのHTTPClient
を使用しています。
しかし、この実装は不完全です。それが唯一の原始的なLM認証をサポートしています。
私はに接続する必要があるシステムは、より最近のNTLM認証時に主張します。
そこで、私のWebサービスは、NTLMとのApache HTTPクライアントを使用するときに認証に失敗しました。
HTTPClient
が認証しようと失敗を停止することはありませんとしてこれは実際にはその後、無限ループに入ります。
ソリューション
JCIFS完全にNTLMハンドシェイクのすべての3つのバージョンをサポートしています。
私は自分自身のクラス(継承を倒すために、それは最終的」として宣言されている)。
org.apache.commons.httpclient.auth.NTLM
を持っています
私は、メソッドを上書きしている。
public String getType3Message(
String user, String password, String host, String domain,
byte[] nonce) throws AuthenticationException
jcifs.ntlmssp.Type3Message
のインスタンスを構築します
そして正しく生成NTML認証を持っているType3Message
を戻すには、このオブジェクトを使用します。
私はその後org.apache.commons.httpclient.auth.AuthScheme
の私自身のインスタンスを作成するために必要な
この新しいNTLMの実装を使用するようにします。コール
org.apache.commons.httpclient.auth.AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, MyNewAuthScheme.class)
私のWSエンドポイントのスタブを起動します。
そして、それは動作します!!!
他のヒント
ヨーヨー非常にベン、良い仕事をありがとうございました。 私の解決策のために私はあなたのクラスに基づいて、2改善を必要としています。
1)のクラスJcifsNtlmScheme の
インターフェイスはJCIFS(Iバージョン1.3.14を使用)に変更されました。 NTLMフラグが、私は本当にわからないが、0x82とは、私の作品、必要とされます。
int flags = Type3Message.NTLMSSP_NEGOTIATE_OEM | Type3Message.NTLMSSP_NEGOTIATE_LM_KEY;
Type3Message msg3 =
new Type3Message(msg2, ntcredentials.getPassword(),
ntcredentials.getDomain(), ntcredentials.getUserName(), ntcredentials.getHost(), flags);
2)のクラスNtlmJcifsCredentials の
DefaultHttpParams.setHttpParamsFactory(paramFact);
これは最初の接続のために正常に動作します。グローバル設定のようです。これはおそらく、本当にスレッドセーフではありません。 私は、接続ベースの資格情報を必要としています。だから私は、このクラスを落とし、挿入された内蔵のオーセンティケータ直接Webサービスのスタブの作成後:
jcifs.Config.setProperty("jcifs.encoding", "ASCII");
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, JcifsNtlmScheme.class);
Authenticator authenticator = new Authenticator();
List<String> authScheme = new ArrayList<String>();
authScheme.add(Authenticator.NTLM);
authScheme.add(Authenticator.BASIC);
authenticator.setAuthSchemes(authScheme);
authenticator.setUsername(myusername);
authenticator.setPassword(mypassword);
authenticator.setHost(servername);
authenticator.setDomain(domain);
exService._getServiceClient().getOptions().setProperty(HTTPConstants.AUTHENTICATE, authenticator);
exService._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, Boolean.FALSE);
exService._getServiceClient().getOptions().setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE);
セルゲイさんのコメントに応えて...
私は、溶液中の2 clasesを持っています。このような認可スキーム
import java.io.IOException;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthChallengeParser;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
import org.apache.commons.httpclient.auth.NTLMScheme;
import org.apache.commons.httpclient.util.EncodingUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* AuthScheme that delegates the work of reading and writing NTLM messages to
* the JCIFS implementation
*
* directly inspired by org.apache.commons.httpclient.auth.NTLMScheme
*
*
* This software is based upon voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*
*/
public class JcifsNtlmScheme implements AuthScheme
{
/** Log object for this class. */
private static final Log LOG = LogFactory.getLog(NTLMScheme.class);
/** NTLM challenge string. */
private String ntlmchallenge = null;
private static final int UNINITIATED = 0;
private static final int INITIATED = 1;
private static final int TYPE1_MSG_GENERATED = 2;
private static final int TYPE2_MSG_RECEIVED = 3;
private static final int TYPE3_MSG_GENERATED = 4;
private static final int FAILED = Integer.MAX_VALUE;
/** Authentication process state */
private int state;
/**
* Default constructor for the NTLM authentication scheme.
*
* @since 3.0
*/
public JcifsNtlmScheme()
{
super();
this.state = UNINITIATED;
}
/**
* Constructor for the NTLM authentication scheme.
*
* @param challenge
* The authentication challenge
*
* @throws MalformedChallengeException
* is thrown if the authentication challenge is malformed
*/
public JcifsNtlmScheme(final String challenge)
throws MalformedChallengeException
{
super();
processChallenge(challenge);
}
/**
* Processes the NTLM challenge.
*
* @param challenge
* the challenge string
*
* @throws MalformedChallengeException
* is thrown if the authentication challenge is malformed
*
* @since 3.0
*/
public void processChallenge(final String challenge)
throws MalformedChallengeException
{
String s = AuthChallengeParser.extractScheme(challenge);
if (!s.equalsIgnoreCase(getSchemeName()))
{
throw new MalformedChallengeException("Invalid NTLM challenge: "
+ challenge);
}
int i = challenge.indexOf(' ');
if (i != -1)
{
s = challenge.substring(i, challenge.length());
this.ntlmchallenge = s.trim();
this.state = TYPE2_MSG_RECEIVED;
}
else
{
this.ntlmchallenge = "";
if (this.state == UNINITIATED)
{
this.state = INITIATED;
}
else
{
this.state = FAILED;
}
}
}
/**
* Tests if the NTLM authentication process has been completed.
*
* @return true if Basic authorization has been processed,
* false otherwise.
*
* @since 3.0
*/
public boolean isComplete()
{
return this.state == TYPE3_MSG_GENERATED || this.state == FAILED;
}
/**
* Returns textual designation of the NTLM authentication scheme.
*
* @return ntlm
*/
public String getSchemeName()
{
return "ntlm";
}
/**
* The concept of an authentication realm is not supported by the NTLM
* authentication scheme. Always returns null
.
*
* @return null
*/
public String getRealm()
{
return null;
}
/**
* Unsupported.
*/
public String getID()
{
throw new UnsupportedOperationException();
}
/**
* Returns the authentication parameter with the given name, if available.
*
*
* There are no valid parameters for NTLM authentication so this method
* always returns null.
*
*
* @param name
* The name of the parameter to be returned
*
* @return the parameter with the given name
*/
public String getParameter(String name)
{
if (name == null)
{
throw new IllegalArgumentException("Parameter name may not be null");
}
return null;
}
/**
* Returns true. NTLM authentication scheme is connection based.
*
* @return true.
*
* @since 3.0
*/
public boolean isConnectionBased()
{
return true;
}
/**
* Unsupported.
*/
public static String authenticate(
final NTCredentials credentials, final String challenge)
throws AuthenticationException
{
throw new UnsupportedOperationException();
}
/**
* Unsupported.
*/
public static String authenticate(
final NTCredentials credentials, final String challenge,
String charset) throws AuthenticationException
{
throw new UnsupportedOperationException();
}
/**
* Unsupported.
*/
public String authenticate(
Credentials credentials, String method, String uri)
throws AuthenticationException
{
throw new UnsupportedOperationException();
}
/**
* Produces NTLM authorization string for the given set of
* {@link Credentials}.
*
* @param credentials
* The set of credentials to be used for athentication
* @param method
* The method being authenticated
*
* @throws InvalidCredentialsException
* if authentication credentials are not valid or not applicable
* for this authentication scheme
* @throws AuthenticationException
* if authorization string cannot be generated due to an
* authentication failure
*
* @return an NTLM authorization string
*
* @since 3.0
*/
public String authenticate(Credentials credentials, HttpMethod method)
throws AuthenticationException
{
LOG.trace("enter NTLMScheme.authenticate(Credentials, HttpMethod)");
if (this.state == UNINITIATED)
{
throw new IllegalStateException(
"NTLM authentication process has not been initiated");
}
NTCredentials ntcredentials = null;
try
{
ntcredentials = (NTCredentials) credentials;
}
catch (ClassCastException e)
{
throw new InvalidCredentialsException(
"Credentials cannot be used for NTLM authentication: "
+ credentials.getClass().getName());
}
byte[] msgBytes = null;
String response = null;
if (this.state == INITIATED)
{
Type1Message msg = new Type1Message();
// @see http://davenport.sourceforge.net/ntlm.html#theType1Message
// dont' support Unicode
// negotiate OEM
// request authentication realm in Type2 response
// not signed
// not encrypted
// not authenticated
// no lan manager key
// negotiate NTLM
msg.setFlags(0x5206);
msg.setSuppliedWorkstation(ntcredentials.getHost());
msg.setSuppliedDomain(ntcredentials.getDomain());
msgBytes = msg.toByteArray();
this.state = TYPE1_MSG_GENERATED;
}
else if (this.state == TYPE2_MSG_RECEIVED)
{
byte[] msg2Bytes =
Base64.decodeBase64(EncodingUtil.getBytes(
this.ntlmchallenge,
method.getParams().getCredentialCharset()));
try
{
Type2Message msg2 = new Type2Message(msg2Bytes);
Type3Message msg3 =
new Type3Message(msg2, ntcredentials.getPassword(),
ntcredentials.getDomain(), ntcredentials
.getUserName(), ntcredentials.getHost());
msgBytes = msg3.toByteArray();
}
catch (IOException ex)
{
throw new AuthenticationException(
"unable to parse Type2Message", ex);
}
this.state = TYPE3_MSG_GENERATED;
}
else
{
throw new RuntimeException("failed to authenticate");
}
response = EncodingUtil.getAsciiString(Base64.encodeBase64(msgBytes));
return "NTLM " + response;
}
}
そして、このような認証スキームを登録するには、クラス、
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.NTCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
import org.apache.commons.httpclient.auth.CredentialsProvider;
import org.apache.commons.httpclient.params.DefaultHttpParams;
import org.apache.commons.httpclient.params.DefaultHttpParamsFactory;
import org.apache.commons.httpclient.params.HttpParams;
/**
* registers NTLM authentication for apache axis
*
*/
public class NtlmJcifsCredentials
{
public static void register(String password)
{
final String username = System.getProperty("user.name");
final String computername = System.getenv("COMPUTERNAME");
final String userDomain = System.getenv("USERDOMAIN");
register(username, password, computername, userDomain);
}
public static void register(String username, String password, String userDomain)
{
final String computername = System.getenv("COMPUTERNAME");
register(username, password, computername, userDomain);
}
public static void register(
String username, String password, String computername, String domain)
{
final NTCredentials ntCred =
new NTCredentials(username, password, computername, domain);
final CredentialsProvider ntlmCredProvider = new CredentialsProvider()
{
public Credentials getCredentials(
AuthScheme scheme, String host, int port, boolean proxy)
throws CredentialsNotAvailableException
{
return ntCred;
}
};
final DefaultHttpParamsFactory paramFact =
new DefaultHttpParamsFactory()
{
@Override
protected HttpParams createParams()
{
HttpParams htp = super.createParams();
htp.setParameter(
CredentialsProvider.PROVIDER,
ntlmCredProvider);
return htp;
}
};
DefaultHttpParams.setHttpParamsFactory(paramFact);
// we want all our jcifs encoding to be ascii
jcifs.Config.setProperty("jcifs.encoding", "ASCII");
// our jcifs implemented NTLM is required for MDW's authentication
AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, JcifsNtlmScheme.class);
}
}
実行時に私が呼ん
NtlmJcifsCredentials.register(username, password, domain)
私は自分のエンドポイントスタブを構築し、それだけで動作します。 デフォルトのApache Commonsのクラスを無限に接続しようとし続けます - - NTLMの場合は簡単にアカウントがWindowsからロックアウトされることにつながることがある。の認証に失敗した場合ならば、有益な副作用として、これは単に例外をチャックしますP>
私はそれが働いて持っているが、私はまだHTTPのプロキシサーバのサポートを実装していませんでした。 http://www.magsoft.nl/share/Axis2%20patch.zip 私が使用するすべてのjarファイルは、プロジェクトのlibディレクトリにあります。 いくつかのクラスパスの要件があります。最初のAxis2 HTTPClient4 patch.jarは軸ジャー上になければなりません。さらに、コモンズ-にHTTPClient-3.1.jarをクラスパスではなく、HTTPClientの-4瓶の後に、まだする必要があります。
ここで私は、クライアントを実装する方法です。
Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);
SchemeRegistry sr = new SchemeRegistry();
sr.register(http);
HttpParams httpParms = new BasicHttpParams();
ClientConnectionManager connManager = new ThreadSafeClientConnManager(httpParms, sr);
DefaultHttpClient httpclient = new DefaultHttpClient(connManager, httpParms);
httpclient.getAuthSchemes().register(HttpTransportProperties.Authenticator.NTLM, new NTLMSchemeFactory());
httpclient.getCredentialsProvider().setCredentials(new AuthScope(host, -1), new NTCredentials(user, pass, host, domain));
sps = new SharepointServiceStub(addr.toString());
List authScheme = new ArrayList();
authScheme.add(HttpTransportProperties.Authenticator.NTLM);
HttpTransportProperties.Authenticator auth = new HttpTransportProperties.Authenticator();
auth.setHost(host);
auth.setDomain(domain);
auth.setUsername(user);
auth.setPassword(pass);
auth.setAuthSchemes(authScheme);
Options options = sps._getServiceClient().getOptions();
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.REUSE_HTTP_CLIENT, true);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CACHED_HTTP_CLIENT, httpclient);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, auth);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, Boolean.TRUE);
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.CONNECTION_TIMEOUT, 900000); // 15 minutes
options.setProperty(org.apache.axis2.transport.http.HTTPConstants.SO_TIMEOUT, 180000); // 3 minutes
しかし、あなたは次のツリーのクラスが必要になります、これが機能するためには: NTLMSchemeFactory.java
package ...;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthSchemeFactory;
import org.apache.http.impl.auth.NTLMScheme;
import org.apache.http.params.HttpParams;
public class NTLMSchemeFactory implements AuthSchemeFactory
{
public NTLMSchemeFactory()
{
}
public AuthScheme newInstance(final HttpParams params)
{
return new NTLMScheme(new JCIFSEngine());
}
}
JCIFSScheme.java
package ...;
import org.apache.http.impl.auth.NTLMScheme;
public class JCIFSScheme extends NTLMScheme
{
public JCIFSScheme()
{
super(new JCIFSEngine());
}
}
JCIFSEngine.java
package ...;
import java.io.IOException;
import jcifs.ntlmssp.Type1Message;
import jcifs.ntlmssp.Type2Message;
import jcifs.ntlmssp.Type3Message;
import jcifs.util.Base64;
import org.apache.http.impl.auth.NTLMEngine;
import org.apache.http.impl.auth.NTLMEngineException;
public class JCIFSEngine implements NTLMEngine
{
public String generateType1Msg(String domain, String workstation) throws NTLMEngineException
{
Type1Message t1m = new Type1Message(Type1Message.getDefaultFlags(), domain, workstation);
return Base64.encode(t1m.toByteArray());
}
public String generateType3Msg(String username, String password, String domain, String workstation, String challenge)
throws NTLMEngineException
{
Type2Message t2m;
try
{
t2m = new Type2Message(Base64.decode(challenge));
} catch (IOException ex)
{
throw new NTLMEngineException("Invalid Type2 message", ex);
}
Type3Message t3m = new Type3Message(t2m, password, domain, username, workstation, 0);
return Base64.encode(t3m.toByteArray());
}
}
この Axis2Patch.zip のは、本当の命の恩人となっています。 これは私がやったことです。
はNTLMv2がで構築していhttpclient4.1ベータ1でコンパイルさAxis2Patch。 私のプロジェクトにそれをインポートしてもhttpclient4.1beta1を輸入しました。
私はこのような私の輸入を変更しました
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.NTLMScheme;
//import org.apache.commons.httpclient.NTCredentials;
//import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.params.AuthPolicy;
、あまりにも多くのコードを変更せずに、それは完璧に動作します。 ありがとう!