레이블이 jersey인 게시물을 표시합니다. 모든 게시물 표시
레이블이 jersey인 게시물을 표시합니다. 모든 게시물 표시

2013년 12월 7일 토요일

Secure RESTful web service (HTTPS, SSL를 사용하는) 접속 방법

이전 블로그에서 이전 함 (원본 글 2013/12/07 작성)

한줄로 말해 
HTTPS 프로토콜로 접속을 해야 하는 RESTful web service를 위한 접속 방법에 대한 설명 (jersey를 사용)

자세한 것은 아래 링크에서 읽어 보면 되며 ....

Calling / Invoking Secure RESTful Web Service over HTTPS with JAX-RS in Java without Keystore & Truststore Information
 Posted by MyBhavesh on Dec 25, 2012 in Technical Blog | 0 comments
 The article is written for/using J2SE 6, Jersey 1.1.4.1 and Eclipse IDE for Java EE Developers [Ganymede].

그냥 마지막 샘플 코드를 수정해서 사용하면 ok 일듯..

다른 예제들을 찾아보긴 했는데 여기 예제가 제일 깔끔한듯하다. (Stackoverflow에서 무슨 공격에 취약해 질 수 있다는 보안 관련 언급이 있었는데 찾지는 못해서 적지는 못했음.)
SecureRestClientTrustManager, SecureRestClient 를 머지하고 jersey client만 생성하는 helper class로 수정 함.

 public class SSLClientHelper {

public static ClientConfig configureClient() {
TrustManager[ ] certs = new TrustManager[ ] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
}
};
SSLContext ctx = null;
try {
ctx = SSLContext.getInstance("TLS");
ctx.init(null, certs, new SecureRandom());
} catch (java.security.GeneralSecurityException ex) {
}
HttpsURLConnection.setDefaultSSLSocketFactory(ctx.getSocketFactory());

ClientConfig config = new DefaultClientConfig();
try {
config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties(
new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}, 
ctx
));
} catch(Exception e) {
}
return config;
}

public static Client createClient() {
return Client.create(SSLClientHelper.configureClient());
}
}

  Client client = null;
WebResource webResource = null;
JSONObject object = null;

try{
ServiceFind er.setIteratorProvider(new AndroidServiceIteratorProvider<Object>());

client = SSLClientHelper.createClient();
webResource = client.resource(wimple.getServicehost() + path);
ClientResponse response = webResource.type("application/x-www-form-urlencoded").post(ClientResponse.class, params);
String output = response.getEntity(String.class);
..... 생략....

 
* 참고로 Android에서 jersey를 사용하려면 아래의 글을 참고하여 추가 적인 helper class를 사용할 필요 있음.


2013년 6월 18일 화요일

Android Jersey 사용 시 WebResource type 설정 시 NullPointerException

이전 블로그에서 이전 함 (원본 글 2013/06/18 작성)

Android 상에서 Jersey(버전은 1.17.1)를 사용하여 REST를 처리 시
WebResoruce의 type을 설정하는데 NullPointerException이 발생하여 찾다 보니
아래와 같은 article 검색

Android 의 APK packaging 문제로 META-INF/service 들을 못찾는다는 얘기... 사실 잘 모르겠다.. :(

Reply | Threaded | More     star

Re: java.lang.NullPointerException on Android

Lucas Ventura
6 posts
Paul Sandoz wrote
On May 28, 2010, at 11:21 AM, Lucas Ventura wrote: I would be surprised if ClassLoader.getResources ceased to function correctly to load resources (that method is used to load the META-INF/ services files). But a quick search does indicate others are having similar issues with packaging and META-INF/services.
The problem after inspecting a little bit, is that the ClassLoader created by Google neither can't find services files, nor the class implementations.
Paul Sandoz wrote
There might be a way. It is possible to override the META-INF/services lookup by using the following method: https://jersey.dev.java.net/nonav/apidocs/latest/jersey/com/sun/jersey/spi/service/ServiceFinder.html #setIteratorProvider %28com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider%29 So you could provide your own implementation. Paul.
So I've provided a hardcoded implementation with the names of the classes indicateds in the META-INF/services files. The question is: when I should do this call to serIteratorProvider()? Because if I do before the Client creation it is looking for servicejersey-client-components. If I do after, it works, but... will be called again with a that kind of serviceName? Thanks a lot :)


암튼 해결책이 위쪽 thread와 아래 link에 있어 일단 추가하여 수정
그리고 추가로 아래 해결책의 update 사항에 Android maven plugin에서는 해결되어 있다니.. 나중에 참고해 보자..



up vote12down voteaccepted
Paul's suggestion is correct. I got a little bit deeper in that subject and found a reason.
Android apk packaging tool (APKBuilder class from sdklib.jar) ignores different folders while it creates the package (source). One of those folders is META-INF - no matter if its in the attached library or in the project's source folder.
Workaround for version 1.8 (and probably other also, but I didn't test it) of Jersey is to provide custom (default one looks up META-INF/services/ which is not present in android apk) implementation forServiceFinder$ServiceIteratorProvider which has hard coded provider class names. I based my implementation on this implementation proposed by Lucas:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import android.util.Log;

import com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider;

public class AndroidServiceIteratorProvider<T> extends ServiceIteratorProvider<T> {

    private static final String TAG = AndroidServiceIteratorProvider.class.getSimpleName();
    private static final String MESSAGE = "Unable to load provider";

    private static final HashMap<String, String[]> SERVICES = new HashMap<String, String[]>();

    private static final String[] com_sun_jersey_spi_HeaderDelegateProvider = {
            "com.sun.jersey.core.impl.provider.header.MediaTypeProvider",
            "com.sun.jersey.core.impl.provider.header.StringProvider"
    };

    private static final String[] com_sun_jersey_spi_inject_InjectableProvider = { 
    };

    private static final String[] javax_ws_rs_ext_MessageBodyReader = {
            "com.sun.jersey.core.impl.provider.entity.StringProvider",
            "com.sun.jersey.core.impl.provider.entity.ReaderProvider"
    };

    private static final String[] javax_ws_rs_ext_MessageBodyWriter = {
            "com.sun.jersey.core.impl.provider.entity.StringProvider",
            "com.sun.jersey.core.impl.provider.entity.ReaderProvider"
    };

    static {
        SERVICES.put("com.sun.jersey.spi.HeaderDelegateProvider",
                com_sun_jersey_spi_HeaderDelegateProvider);
        SERVICES.put("com.sun.jersey.spi.inject.InjectableProvider",
                com_sun_jersey_spi_inject_InjectableProvider);
        SERVICES.put("javax.ws.rs.ext.MessageBodyReader",
                javax_ws_rs_ext_MessageBodyReader);
        SERVICES.put("javax.ws.rs.ext.MessageBodyWriter",
                javax_ws_rs_ext_MessageBodyWriter);
        SERVICES.put("jersey-client-components", new String[]{});
        SERVICES.put("com.sun.jersey.client.proxy.ViewProxyProvider", new String[]{});
    }

    @SuppressWarnings("unchecked")
    @Override
    public Iterator<Class<T>> createClassIterator(Class<T> service,
            String serviceName, ClassLoader loader,
            boolean ignoreOnClassNotFound) {

        String[] classesNames = SERVICES.get(serviceName);
        int length = classesNames.length;
        ArrayList<Class<T>> classes = new ArrayList<Class<T>>(length);
        for (int i = 0; i < length; i++) {
            try {
                classes.add((Class<T>) Class.forName(classesNames[i]));
            } catch (ClassNotFoundException e) {
                Log.v(TAG, MESSAGE,e);
            }
        }
        return classes.iterator();
    }

    @Override
    public Iterator<T> createIterator(Class<T> service, String serviceName,
            ClassLoader loader, boolean ignoreOnClassNotFound) {

        String[] classesNames = SERVICES.get(serviceName);
        int length = classesNames.length;
        ArrayList<T> classes = new ArrayList<T>(length);
            for (int i = 0; i &lt; length; i++) {
            try {
                classes.add(service.cast(Class.forName(classesNames[i])
                        .newInstance()));
            } catch (IllegalAccessException e) {
                Log.v(TAG, MESSAGE,e);
            } catch (InstantiationException e) {
                Log.v(TAG, MESSAGE,e);
            } catch (ClassNotFoundException e) {
                Log.v(TAG, MESSAGE,e);
            }
        }

        return classes.iterator();
    }
}
I removed most of the classes since I didn't use them and also they were causing verification errors on dalvik vm...
The above code should be used as follows:
ServiceFinder.setIteratorProvider(new AndroidServiceIteratorProvider());
Client client = Client.create();
EDIT:
It seems that the problem have been fixed in android-maven-plugin.
mosa...@gmail.com wrote:
The pull request with the fix was merged into master and will be released with 3.2.1:
share|improve this answer