2016-05-31 8 views
2

안녕하십니까.apache로 사용자 토큰 암호화 cxf

나는 소비하고자하는 비누 웹 서비스를 가지고 있습니다. 저는 실제 프로젝트에서 특히 사용자 이름 토큰 암호화에 필요한 것을 시뮬레이션하기 위해 작은 프로젝트를 만들었습니다.

  • 가 암호화되지 않은 암호 값을 쓰기 : 아래에 나열된

    는 클라이언트 측에서 암호를 암호화하는 방법을 제공하는 단계가 있습니다.

  • 그런 다음 1 단계에서 만든 데이터 블록을 암호 키 인증서의 공용 부분으로 암호화합니다. RSA 알고리즘을 사용하고 PKCS # 1.5 패딩 (OAEP 아님)을 사용하여 암호화 된 스트림에 결과를 추가합니다. 이는 API를 통해 제출 된 암호화 된 비밀번호가됩니다.
  • 결과 암호화 된 바이트 배열을 base64 인코딩을 사용하는 문자열로 변환합니다. 이 Base64로 인코딩 된 문자열을 API 요청에 개시 자 SecurityCredential 값으로 제공하십시오.
  • 이 목적으로 초 기자에게 발급 된 X509 인증서에서 공개 키로 암호화 할 비밀번호입니다.

지금까지 클라이언트와 서버를 만들었으며 요청을 보내고 응답을받을 수있었습니다.

또한 ClientPasswordCallback 클래스에 암호가있는 사용자 이름 토큰을 전달하고 ServerPasswordCallback 클래스에서 이러한 자격 증명을 확인하여 웹 서비스를 보호 할 수 있습니다.

나는 더 나아가와 별도의 요청에 WSS4J를 사용하여 메시지의 본문 부분을 암호화 한 RSA, 내가의 PrivateKey에 저장된 clientKey.jks 및 개인 키를 공개 키를 저장 한 이에 X509 .jks 및 클라이언트 및 서버 암호 콜백 핸들러에 적절한 암호를 제공함으로써 클라이언트에서 본문 부분을 암호화하고 서버에서 해독 할 수있었습니다.

챌린지 : 내가 겪고있는 주된 도전 과제는 공개 키를 사용하여 사용자 이름 토큰의 암호를 암호화하고 동일한 암호를 해독 할 수 있도록 위의 두 단계를 단일 요청에서 결합하는 것입니다. 서버 측은 개인 키를 사용합니다.

NB jdk와 함께 제공되는 keygen 도구를 사용하여 테스트 용 키를 생성했습니다.

ClientPasswordCallback 클래스에는 clientKey.jks 키 저장소와 암호화해야 할 다른 암호가 두 개인 암호가 있다고 생각합니다.

클라이언트 측

TestMathUtility 클래스

public static void main(String[] args) { 

    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); 

    // Use the URL defined in the soap address portion of the WSDL 
    factory.setAddress("http://localhost:8080/MathUtility/services/MathUtilityPort"); 

    // Utilize the class which was auto-generated by Apache CXF wsdl2java 
    factory.setServiceClass(MathUtility.class); 

    Object client = factory.create(); 

    // Adding Logging Interceptors 
    LoggingOutInterceptor loggingOutInterceptor = new LoggingOutInterceptor(); 
    loggingOutInterceptor.setPrettyLogging(true); 
    ClientProxy.getClient(client).getOutInterceptors().add(loggingOutInterceptor); 

    LoggingInInterceptor loggingInInterceptor = new LoggingInInterceptor(); 
    loggingInInterceptor.setPrettyLogging(true); 
    ClientProxy.getClient(client).getInInterceptors().add(loggingInInterceptor); 

    // Set up WS-Security Encryption 
    // Reference: https://ws.apache.org/wss4j/using.html 
    Map<String, Object> props = new HashMap<String, Object>(); 
    props.put(WSHandlerConstants.USER, "testkey"); 
    props.put(WSHandlerConstants.ACTION, WSHandlerConstants.ENCRYPT); 
    props.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordText"); 
    props.put(WSHandlerConstants.ENC_PROP_FILE, "clientKeystore.properties"); 
    props.put(WSHandlerConstants.ENCRYPTION_PARTS, "{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"); 
    props.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordCallback.class.getName()); 

    WSS4JOutInterceptor wss4jOut = new WSS4JOutInterceptor(props); 

    ClientProxy.getClient(client).getOutInterceptors().add(wss4jOut); 

    try { 

     // Call the Web Service to perform an operation 
     int response = ((MathUtility)client).addIntegers(5, 10); 

     System.out.println("Response we've got ========= "+response); 

     } catch (SecurityException e) { 
     e.printStackTrace(); 
     } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
     } 

} 

ClientPasswordCallback 클래스

public class ClientPasswordCallback implements CallbackHandler { 

@Override 
public void handle(Callback[] callbacks) throws IOException, 
     UnsupportedCallbackException { 

    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0]; 

    // set the password for our message. 
    pc.setPassword("clientstorepass"); 

} 
을 :

는 지금까지 보관할 수 있었을 것입니다 6,

}

서버 측

MathUtility 클래스

@WebService(targetNamespace = "http://utility.math.com/", portName =  "MathUtilityPort", serviceName = "MathUtilityService") 
public class MathUtility { 

public int addIntegers(int firstNum, int secondNum) { 
    return firstNum + secondNum; 
} 

public int factorial(int n) { 
    int result = 1; 

    for (int i = 1; i <= n; i++) { 
     result = result * i; 
    } 

    return result; 
} 
} 

ServerPasswordCallback 클래스

public class ServerPasswordCallback implements CallbackHandler { 

@Override 
public void handle(Callback[] arg0) throws IOException, 
     UnsupportedCallbackException { 

    WSPasswordCallback pc = (WSPasswordCallback) arg0[0]; 

    // set the password for our message. 
    pc.setPassword("storepass"); 

} 

} 

CXF-beans.xml 환경

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xmlns:jaxws="http://cxf.apache.org/jaxws" 
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> 
<import resource="classpath:META-INF/cxf/cxf.xml" /> 
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> 
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> 

<bean id="myPasswordCallback" class="com.math.utility.security.ServerPasswordCallback"/> 

<jaxws:endpoint xmlns:tns="http://utility.math.com/" id="mathutility" 
    implementor="com.math.utility.MathUtility" wsdlLocation="wsdl/mathutility.wsdl" 
    endpointName="tns:MathUtilityPort" serviceName="tns:MathUtilityService" 
    address="/MathUtilityPort"> 
    <jaxws:features> 
     <bean class="org.apache.cxf.feature.LoggingFeature" /> 
    </jaxws:features> 

     <jaxws:inInterceptors> 
      <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"> 
      <constructor-arg> 
       <map> 
        <entry key="user" value="testkey"/> 
        <entry key="action" value="Encrypt"/> 
        <entry key="passwordType" value="PasswordText"/> 
        <entry key="decryptionParts" value="{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/> 
        <entry key="decryptionPropFile" value="serverKeystore.properties"/> 
        <entry key="passwordCallbackRef"> 
         <ref bean="myPasswordCallback"/> 
        </entry> 
       </map> 
      </constructor-arg> 
      </bean> 

     </jaxws:inInterceptors> 

</jaxws:endpoint> 

clientKeyStore.properties 동일한 구조가 서버 측에서 사용 제공되지 않은 사용

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin 
org.apache.ws.security.crypto.merlin.keystore.file=clientkeystore.jks 
org.apache.ws.security.crypto.merlin.keystore.password=clientstorepass 
org.apache.ws.security.crypto.merlin.keystore.type=jks 

.jks 파일 파일

NB 봄을 사용하지 않습니다. 사용자 정의 당신이 당신의 웹 서비스에를 연결하려면 방법 verifyCustomPassword(UsernameToken usernameToken, RequestData data) in UsernameTokenValidator

을 무시할 수 소화 갖고 싶어

답변

0

다른 SO-question에 대한 내 대답을 살펴 있습니다. 이 답변의 필수 요소는 다음과 같습니다

<property name="wssConfig"> 
     <ref bean="usernameTokenWssConfig"/> 
</property> 

그리고 당신의 코드베이스에 참조 된 클래스를 추가 :

@Component("usernameTokenWssConfig") 
public class UsernameTokenWssConfig extends WSSConfig { 
    public UsernameTokenWssConfig() { 
     setValidator(WSSecurityEngine.USERNAME_TOKEN, new CustomUsernameTokenValidator()); 
     setRequiredPasswordType(WSConstants.CUSTOM_TOKEN); 
    } 
} 
+0

안녕 프랭크, 당신의 시간 및 입력 주셔서 감사합니다. 공개 키를 사용하여 암호를 암호화하고 싶습니다. 나는 클라이언트 코드에서 이와 같은 일을하기를 고대하고있다 :'props.put (WSHandlerConstants.ENCRYPTION_PARTS, "{Content} {http://schemas.xmlsoap.org/soap/envelope/} Body"), ' – chilopoda

+0

하지만 Body를 암호화하는 대신 UserNameKoken 부분 만 암호화되도록 UsernameToken으로 변경해야합니다. 가능한가요 아니면 암호로 제안한대로 암호를 암호화 한 다음 헤더에 전달해야합니까? – chilopoda

+0

안녕하세요, 암호를 일반 텍스트 또는 다이제스트로 보낼 수 있습니다. 이는 한쪽으로 해시되었음을 의미합니다. 암호를 암호화하고 암호를 해독해야하는 경우 내 제안 솔루션을 사용해야합니다. – Frank