apache 축으로 JCIFS가 멋지게 재생되도록하려면 어떻게해야합니까?

StackOverflow https://stackoverflow.com/questions/916820

  •  06-09-2019
  •  | 
  •  

문제

Apache Axis 1.4를 NTLM 인증을 사용하여 작업에 대한 액세스를 제한하는 웹 서비스에 연결해야합니다. NTLM 핸드 셰이크를 처리하기 위해 Samba JCIF를 사용하기를 기대합니다.

나는 찾았다

http://hc.apache.org/httpcomponents-client/ntlm.html

httpclient 4.0을 JCIF로 연결하는 방법에 대한 환상적인 지시를 제공합니다.

문제는 Axis가 HTTP Client 3.0을 사용하고 두 개의 API가 매우 다르게 보입니다.

내가 볼 수있는 2 가지 가능성이 있습니다

  1. httpclient 4에 꽂을 수있는 축의 객체를 작성하십시오.
  2. samba jcifs로 httpclient 3.0을 연결하는 방법을 알아 봅니다.

번호 1. 사소한 모습을 보이지만 가능한 번호 2. 웹 에서이 작업을 수행하는 방법을 설명하는 고무적인 메시지를 찾을 수 없습니다.

내 질문은 : Samba JCIF를 Httpclient 3.0과 성공적으로 연결 한 사람이 있습니까? Httpclient 4와 함께 작동하는 축 httpsender 객체를 이미 만든 사람이 있습니까?

내가 고려하지 않은 더 나은 대안이 있습니까?

도움이 되었습니까?

해결책

마지막으로 이것에 대한 해결책이 있습니다.

문제

Apache Axis는 Apache를 사용합니다 HTTPClient 자체 NTLM 구현을 제공합니다.
그러나이 구현은 불완전합니다. 원시 LM 인증 만 지원합니다.
최신 NTLM 인증을 고집하기 위해 연결 해야하는 시스템.

따라서 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이 개체를 사용하여 a를 반환하십시오 Type3Message NTML 인증이 올바르게 생성되었습니다.

그런 다음 나만의 인스턴스를 만들어야했습니다 org.apache.commons.httpclient.auth.AuthScheme이 새로운 NTLM 구현을 사용합니다. 전화org.apache.commons.httpclient.auth.AuthPolicy.registerAuthScheme(AuthPolicy.NTLM, MyNewAuthScheme.class)

내 WS 엔드 포인트 스텁을 시작하십시오.

그리고 그것은 작동합니다 !!!

다른 팁

대단히 감사합니다 벤, 잘 했어. 내 솔루션의 경우 수업에 따라 두 가지 개선이 필요합니다.

1) 클래스 jcifsntlmscheme

인터페이스가 JCIFS에서 변경되었습니다 (버전 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);

이것은 첫 번째 연결에 적합합니다. 글로벌 설정 인 것 같습니다. 아마도 실제로 스레드 안전이 아닐 수도 있습니다. 연결 기반의 자격 증명이 필요합니다. 그래서 나는이 클래스를 삭제하고 웹 서비스 스터브를 만든 직후에 내장 인증자를 삽입했습니다.

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);

Sergey의 의견에 대한 응답으로 ...

내 솔루션에 두 개의 클라스가 있습니다. 이와 같은 승인 체계


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.
     * 
     * 

* NTLM 인증에는 유효한 매개 변수가 없으므로이 방법 *은 항상 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에서 계정이 잠겨 있도록 쉽게 연결할 수 있습니다.

작동했지만 아직 HTTP에서 프록시 서버 지원을 구현하지 않았습니다.http://www.magsoft.nl/share/axis2%20patch.zip내가 사용하는 모든 항아리는 프로젝트 Lib 디렉토리에 있습니다. 몇 가지 클래스 경로 요구 사항이 있습니다. 먼저 axis2 httpclient4 patch.jar는 축 항아리 위에 있어야합니다. 또한 Commons-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 Beta1을 사용하여 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;

코드 변경이 너무 많지 않으면 완벽하게 작동합니다. 감사!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top