2012년 6월 20일 수요일

enum 사용

간단한 선언
예)
public enum Types {
 TYPE1, TYPE2, TYPE3;
}

String 값을 대입
선언 예)
public enum Types {
 TYPE1("Type 1"),
 TYPE2("Type 2"),
 TYPE3("Type 3");

 private String name;
 Types(String name) {
  this.name = name;
 }

 @Override
 public String toString() {
  return name;
 }
}

사용 예)
package com.enumtest;

public class EnumTest {
 public static void main(String[] args) throws Exception {
  Types type = Types.TYPE1;
  System.out.println(type);
 }
}

결과:
Type 1

2012년 6월 4일 월요일

Ant 사용

소개


Command line 으로 java 프로젝트를 빌드하기에는 패키지명까지 일일이 적어야 하는 번거로움이 있기 때문에 빌드를 도와주는 빌드 시스템을 주로 이용하게 되며 그 중 ant 빌드 시스템 사용법을 기술


1. Ant 설치

  1. 다운로드 : http://ant.apache.org/bindownload.cgi
  2. 원하는 경로에 압축을 해제
  3. $ANT_HOME/bin 경로를 PATH 환경 변수에 추가

2. 소스 코드 및 build.xml 작성

예제 project : hello

최종 폴더 구조
hello/
 + src/
   + com/sample/hello/
     + Hello.java
 + build.xml
 + dist/
   + com/sample/hello/
     + Hello.class

Hello.java
package com.sample.hello;

public class Hello {
 public static void main(String[] args) throws Exception {
  System.out.println("Hello!");
 }
}

build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="hello" default="compile">

 <property name="build.dir" location="dist" />

 <target name="compile">
  <mkdir dir="${build.dir}" />
  <javac destdir="${build.dir}" source="1.6" target="1.6" debug="true"
   deprecation="false" optimize="false" failonerror="true">
   <src path="src" />
  </javac>
 </target>
</project>

설명
  • project - root 노드
    • default 속성 - ant 수행시 기본으로 수행할 target 지정
  • property - variable 지정
  • target - 작업 수행 단위
  • mkdir - 폴더 생성
  • javac - java compile
  • src - 소스 경로 지정

3. compile 하기

$ pwd
/path/to/hello
$ ant compile

4. 실행하기

$ pwd
/path/to/hello
$ java -cp dist com.sample.hello.Hello
Hello!

!) Ant 로 실행하기
아래 코드를 project 태그 안에 추가한다.
<target name="run">
 <java classname="com.sample.hello.Hello">
  <classpath>
   <pathelement location="${build.dir}" />
  </classpath>
 </java>
</target>

실행
$ ant run
Buildfile: /path/to/hello/build.xml

run:
[java] Hello!

BUILD SUCCESSFUL
Total time: 0 seconds


Timestamp
tstamp 태그를 이용한다.
참고: http://ant.apache.org/manual/Tasks/tstamp.html
예)
<tstamp>
    <format property="TODAY_UK" pattern="d-MMMM-yyyy" locale="en,UK" />
</tstamp>
또는
<tstamp>
    <format property="today" pattern="yyyy-MM-dd_HHmmss" />
</tstamp>

locale 을 지정하지 않으면 시스템 시간대가 사용된다.

특정 폴더의 파일 목록 출력하기
참고: http://stackoverflow.com/questions/1456852/how-can-i-print-a-fileset-to-a-file-one-file-name-per-line
예)
<fileset id="my-file-list" dir="."></fileset>
    <pathconvert pathsep="${line.separator}" property="files" refid="my-file-list"/>
<echo message="${files}"/>

폴더 만들기
참고: http://ant.apache.org/manual/Tasks/mkdir.html
<mkdir dir="${path}" />

파일 복사하기
copy 태그를 이용한다.
예)
<copy todir="${to-dir}">
    <fileset dir="${from-dir}">
    </fileset>

2012년 3월 19일 월요일

HTTPS 통신

참고 - http://docs.oracle.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html

프로젝트명: HTTPSPractice


파일 구성:

 - HttpsClientWithCustomCert.java - 사용자가 만든 인증서를 이용한 서버 인증
 - HttpsClientWithDefaultCACert.java - 공인 인증된 인증서로 서버 인증
 - HttpsClientWithoutValidation.java - 인증 없이 서버 접속
 - SimpleHttpsServer.java - 사용자가 만든 인증키를 이용하는 간단한 HTTPS 서버
 - keystore.jks - 서버(SimpleHttpsServer) 에서 사용하는 인증키 저장소
 - truststore.jks - 클라이언트(HttpsClientWithCustomCert) 에서 서버 인증시 사용하는 인증서 저장소


다음과 같은 순서로 설명
1. HttpsURLConnection 을 이용한 접속 (인증 과정 없음)
2. 공인 인증된 인증서로 서버 인증
3. 사용자가 만든 인증서로 서버 인증


1. HttpsURLConnection 을 이용한 접속 (인증 과정 없음)

인증 과정을 결정하는 부분은 SSLContext.init() 함수이다.
아래 소스에는 init() 함수에 모두 null 을 집어 넣음으로써 인증 과정을 무시하고 서버의 내용물을 받는다.

소스:
package com.test.https.practice;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;


/**
 * 
 */
public class HttpsClientWithoutValidation {
 
 /**
  * 
  * @param urlString
  * @throws IOException
  * @throws NoSuchAlgorithmException
  * @throws KeyManagementException
  */
 public void getHttps(String urlString) throws IOException, NoSuchAlgorithmException, KeyManagementException {
  
  // Get HTTPS URL connection
  URL url = new URL(urlString);  
  HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
  
  // Set Hostname verification
  conn.setHostnameVerifier(new HostnameVerifier() {
   @Override
   public boolean verify(String hostname, SSLSession session) {
    // Ignore host name verification. It always returns true.
    return true;
   }
   
  });
  
  // SSL setting
  SSLContext context = SSLContext.getInstance("TLS");
  context.init(null, null, null);  // No validation for now
  conn.setSSLSocketFactory(context.getSocketFactory());
  
  // Connect to host
  conn.connect();
  conn.setInstanceFollowRedirects(true);
  
  // Print response from host
  InputStream in = conn.getInputStream();
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  String line = null;
  while ((line = reader.readLine()) != null) {
   System.out.printf("%s\n", line);
  }
  
  reader.close();
 }
 
 /**
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  HttpsClientWithoutValidation test = new HttpsClientWithoutValidation();
  test.getHttps("https://www.google.com");
 }
}

결과:


2. 공인 인증된 인증서로 서버 인증

SSLContext.init() 함수의 두번째 인자에 X509TrustManager 를 선언하여 집어 넣었다.
그리고 JRE 를 설치하면 기본적으로 [JRE 경로]/lib/security/cacerts 라는 파일명의 공인 인증된 인증서 저장소 파일이 있다.
해당 인증서 저장소를 이용하여 서버의 인증서를 검사하게 하였다.

소스:
package com.test.https.practice;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 *
 */
public class HttpsClientWithDefaultCACert {
 
 /**
  * 
  * @param urlString
  * @throws IOException
  * @throws NoSuchAlgorithmException
  * @throws KeyManagementException
  */
 public void getHttps(String urlString) throws IOException, NoSuchAlgorithmException, KeyManagementException {
  
  // Get HTTPS URL connection
  URL url = new URL(urlString);  
  HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
  
  // Set Hostname verification
  conn.setHostnameVerifier(new HostnameVerifier() {
   @Override
   public boolean verify(String hostname, SSLSession session) {
    // Ignore host name verification. It always returns true.
    return true;
   }
   
  });
  
  // SSL setting
  SSLContext context = SSLContext.getInstance("TLS");
  context.init(null, new TrustManager[] { new X509TrustManager() {

   @Override
   public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    // client certification check
   }

   @Override
   public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    // Server certification check
    
    try {
     
     // Get trust store
     KeyStore trustStore = KeyStore.getInstance("JKS");
     String cacertPath = System.getProperty("java.home") + "/lib/security/cacerts"; // Trust store path should be different by system platform.
     trustStore.load(new FileInputStream(cacertPath), "changeit".toCharArray()); // Use default certification validation
     
     // Get Trust Manager
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
     tmf.init(trustStore);
     TrustManager[] tms = tmf.getTrustManagers();
     ((X509TrustManager)tms[0]).checkServerTrusted(chain, authType);
     
    } catch (KeyStoreException e) {
     e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    }
    
   }

   @Override
   public X509Certificate[] getAcceptedIssuers() {
    return null;
   }
  } }, null);
  conn.setSSLSocketFactory(context.getSocketFactory());
  
  // Connect to host
  conn.connect();
  conn.setInstanceFollowRedirects(true);
  
  // Print response from host
  InputStream in = conn.getInputStream();
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  String line = null;
  while ((line = reader.readLine()) != null) {
   System.out.printf("%s\n", line);
  }
  
  reader.close();
 }
 
 /**
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  HttpsClientWithDefaultCACert test = new HttpsClientWithDefaultCACert();
  test.getHttps("https://www.google.com");
 }
}

결과:


3. 사용자가 만든 인증서로 서버 인증

우선 인증키 저장소와 인증서 저장소를 만들어 보자.
Portecle 라는 툴을 사용했다.

3.1. 인증키 저장소 만들기(keystore.jks)
3.2. 인증키에서 인증서 추출
3.3. 인증서 저장소 만들기(truststore.jks)

서버는 지정된 인증키 저장소를 이용해 클라이언트에 자신을 인증하는 키를 보내게 된다. 인증과정이 성공하면 클라이언트에 html 내용물을 전달하고 종료한다.
클라이언트는 지정된 인증서 저장소를 이용해 서버를 인증한다. 인증과정이 성공하면 서버로 부터 html 내용물을 전달받는다.

서버 소스:
참고 - http://www.java2s.com/Tutorial/Java/0490__Security/SSLContextandKeymanager.htm
package com.test.https.practice;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

public class SimpleHttpsServer {
 
 public void run(int port) throws NoSuchAlgorithmException, KeyManagementException, IOException, KeyStoreException, CertificateException, UnrecoverableKeyException {
  
  // create ssl context
  SSLContext context = SSLContext.getInstance("TLS");
  
  // set key store
  KeyStore keyStore = KeyStore.getInstance("JKS");
  keyStore.load(new FileInputStream("keystore.jks"), "changeit".toCharArray());
  KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  kmf.init(keyStore, "changeit".toCharArray());
  context.init(kmf.getKeyManagers(), null, null);
  
  // create ssl socket
  SSLServerSocketFactory factory = context.getServerSocketFactory();
  SSLServerSocket socket = (SSLServerSocket)factory.createServerSocket(port);
  SSLSocket client = (SSLSocket)socket.accept();
  InputStream in = client.getInputStream();
  OutputStream out = client.getOutputStream();
  
  // read from client
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  reader.readLine();
  
  // write to client
  BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
  writer.write("HTTP/1.0 200 OK");
  writer.newLine();
  writer.write("Content-Type: text/html");
  writer.newLine();
  writer.newLine();
  writer.write("<html><head><title>Hello</title></head><body>Hellow!</body></html>");
  writer.flush();
  
  // close
  writer.close();
  reader.close();
  client.close();
 }
 
 /**
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  SimpleHttpsServer server = new SimpleHttpsServer();
  server.run(9999);
 }
}


클라이언트 소스:
package com.test.https.practice;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class HttpsClientWithCustomCert {
 
 /**
  * 
  * @param urlString
  * @throws IOException
  * @throws NoSuchAlgorithmException
  * @throws KeyManagementException
  */
 public void getHttps(String urlString) throws IOException, NoSuchAlgorithmException, KeyManagementException {
  
  // Get HTTPS URL connection
  URL url = new URL(urlString);  
  HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
  
  // Set Hostname verification
  conn.setHostnameVerifier(new HostnameVerifier() {
   @Override
   public boolean verify(String hostname, SSLSession session) {
    // Ignore host name verification. It always returns true.
    return true;
   }
   
  });
  
  // SSL setting
  SSLContext context = SSLContext.getInstance("TLS");
  context.init(null, new TrustManager[] { new X509TrustManager() {

   @Override
   public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    // client certification check
   }

   @Override
   public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    
    // Server certification check
    
    try {
     
     // Get trust store
     KeyStore trustStore = KeyStore.getInstance("JKS");
     trustStore.load(new FileInputStream("truststore.jks"), "changeit".toCharArray()); // Use default certification validation
     
     // Get Trust Manager
     TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
     tmf.init(trustStore);
     TrustManager[] tms = tmf.getTrustManagers();
     ((X509TrustManager)tms[0]).checkServerTrusted(chain, authType);
     
    } catch (KeyStoreException e) {
     e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    }
    
   }

   @Override
   public X509Certificate[] getAcceptedIssuers() {
    return null;
   }
  } }, null);
  conn.setSSLSocketFactory(context.getSocketFactory());
  
  // Connect to host
  conn.connect();
  conn.setInstanceFollowRedirects(true);
  
  // Print response from host
  InputStream in = conn.getInputStream();
  BufferedReader reader = new BufferedReader(new InputStreamReader(in));
  String line = null;
  while ((line = reader.readLine()) != null) {
   System.out.printf("%s\n", line);
  }
  
  reader.close();
 }
 
 /**
  * 
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  HttpsClientWithCustomCert test = new HttpsClientWithCustomCert();
  test.getHttps("https://127.0.0.1:9999");
 }
}

결과: