Мыльный клиент Apache CXF, использующий аутентификацию jCIFS SSL + NTLM JDK 5

Я пытаюсь аутентифицироваться на веб-сервисе SOAP с использованием аутентификации NTLM, как упоминалось в Apache CXF со стеком следующим образом:

  • JCIFS-1.3.17.jar
  • CXF-2.7.11
  • NTLM + SSL
  • JDK 5 (возможно, я не могу это изменить)

Каждый раз, когда я пытаюсь подключиться, он отказывается с 401 несанкционированным доступом, потому что он использует мои базовые учетные данные NT, которые не авторизованы, вместо действительных, которые я настроил в коде. (Мне пришлось изменить jCIFS, так как он не поддерживает SSL + NTLM для возврата HTTP-версии NtlmHttpURLConnection). Аналогичный результат, когда используется HTTP Async механизм.

String domainController = "xxx.xxx.xxx";
UniAddress dc = UniAddress.getByName(domainController, true);

jcifs.Config.setProperty("http.auth.ntlm.domain", "xxx.xxx.xxx");
jcifs.Config.setProperty("jcifs.smb.client.domain", "domain");
jcifs.Config.setProperty("jcifs.netbios.wins", dc.getHostAddress());
jcifs.Config.setProperty("jcifs.smb.client.soTimeout", "300000"); // 5 minutes
jcifs.Config.setProperty("jcifs.netbios.cachePolicy", "1200"); // 20 minutes
jcifs.Config.setProperty("jcifs.smb.client.username", USER);
jcifs.Config.setProperty("jcifs.smb.client.password", PWD);

//Register the jcifs URL handler to enable NTLM
jcifs.Config.registerSmbURLHandler();

    HelloWorld src = new HelloWorld();

    ClientProxyFactoryBean factory = new ClientProxyFactoryBean(new JaxWsClientFactoryBean());  

    factory.setServiceClass( IHelloWorld.class );  
    factory.setAddress(SERVICE_URL);
    factory.setUsername(USER);  
    factory.setPassword(PWD);
    IHelloWorld service = (IHelloWorld ) factory.create();

    Client client = ClientProxy.getClient(service);
    HTTPConduit http = (HTTPConduit) client.getConduit();
    System.out.println(http.getClass().getName());
    //org.apache.cxf.transport.http.URLConnectionHTTPConduit

    HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
    httpClientPolicy.setConnectionTimeout(36000);
    httpClientPolicy.setAllowChunking(false);

    http.setClient(httpClientPolicy);
    http.getAuthorization().setAuthorizationType("NTLM");
    http.getAuthorization().setUserName(USER);
    http.getAuthorization().setPassword(PWD);

    http.getClient().setAllowChunking( false );
    http.getClient().setAutoRedirect( true );

    TLSClientParameters tcp = new TLSClientParameters();  
    tcp.setTrustManagers( new TrustManager[]{ new TrustAllX509TrustManager() } );  
    http.setTlsClientParameters( tcp );

    System.out.println("Invoking service...");
    String msg= "echo";
    try {
        String res = service.readMessage(msg);
        System.out.println("readMessage.result=" + res);

    } catch (Exception e) { 
        e.printStackTrace();
    }

При выполнении этого кода я получаю следующую трассировку исключений

: домен \ является неавторизованным пользователем в sun.reflect.NativeConstructorAccessorImpl.newInstance0(собственный метод) в sun.reflect.NativeConstructorAccessorImpl.newInstance(неизвестный источник) в sun.reflect.DelegatingConstructorAccessorImpl.newInstref.javlan.dll не указан.newInstance (Неизвестный источник) в org.apache.cxf.interceptor.ClientFaultConverter.processFaultDetail(ClientFaultConverter.java:175) в org.apache.cxf.interceptor.ClientFaultConverter.handleMessage(ClientFaultConverter.jap: at..phase.PhaseInterceptorChain..java: 69) в org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage (CheckFaultInterceptor.java:34) в org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272) в org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:845) в org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handternaljitConit org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1513) в org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduap.java. at.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) в org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:632) в org.apache.cxf.interceptor.MessageSenderInterceptor (MessageSenderEceptor MessageSenderInterceptor.java:62) в org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272) в org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.jachef70) or5.endpoint.ClientImpl.invoke(ClientImpl.java:479) в org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382) в org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335) в org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96) в org.apache.cxf.frontend.ClientProxy.invoke(ClientProxy.java:81) на com.sun.proxy.$Proxy44.readMessage(неизвестный источник)

2 ответа

Решение

После нескольких часов борьбы, пытаясь совмещать стек JDK 5 с другими SOAP-фреймворками, такими как Axis2 и CXF, я, наконец, сумел справиться с необработанным SOAP-клиентом, который в значительной степени может выполнить ту работу, которая мне нужна. Ниже приведен код, который помог сделать это даже с пользовательскими логинами NT, а не с базовыми.

public final class JCIFSEngine implements NTLMEngine {

    private static final int TYPE_1_FLAGS = NtlmFlags.NTLMSSP_NEGOTIATE_56
            | NtlmFlags.NTLMSSP_NEGOTIATE_128
            | NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2
            | NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN
            | NtlmFlags.NTLMSSP_REQUEST_TARGET;

    public String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS,
                domain, workstation);
        return Base64.encode(type1Message.toByteArray());
    }

    public String generateType3Msg(final String username,
            final String password, final String domain,
            final String workstation, final String challenge)
            throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message",
                    exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message,
                password, domain, username, workstation, type3Flags);
        return Base64.encode(type3Message.toByteArray());
    }

}


public class JCIFSNTLMSchemeFactory implements AuthSchemeProvider {

    public AuthScheme create(final HttpContext context) {
        return new NTLMScheme(new JCIFSEngine());
    }
}

Использование объекта HttpClient для регистрации пользовательских NTLM Engine и реестра схем Auth -

protected Registry<AuthSchemeProvider> getAuthRegistry() {
        Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder
                .<AuthSchemeProvider> create()
                .register(AuthSchemes.NTLM, new JCIFSNTLMSchemeFactory())
                .build();
        return authSchemeRegistry;
    }

protected CredentialsProvider getCredentialsProvider(String user,
            String pass, String domain) {
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST,
                AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM),
                new NTCredentials(user, pass, null, domain));
        return credsProvider;
    }

        HttpClientBuilder httpClientBuilder = HttpClients.custom();
        httpClientBuilder.setDefaultAuthSchemeRegistry(getAuthRegistry());
        httpClientBuilder
                .setDefaultCredentialsProvider(getCredentialsProvider(
                        config.getUserName(), config.getPassword(),
                        config.getDomain()));

        if (config.isProxy()) {
            HttpHost proxy = new HttpHost(config.getProxyHost(),
                    config.getPort());
            httpClientBuilder.setProxy(proxy);
        }

        httpClientBuilder.build();

Надеюсь, это поможет кому-то с подобной проблемой. ура

CXF 2.7.x не поддерживает JDK 5. Из FAQ CXF:

Может ли CXF работать с JDK 1.5?

Да для CXF 2.6.x и старше. Имейте в виду, что Java 2 SE 5.0 с JDK 1.5 достигла конца срока службы (EOL). CXF 2.7.x больше не поддерживает Java 5. Чтобы перейти на 2.7.x, вы должны использовать Java 6 (или новее).

Другие вопросы по тегам