2016-05-31 8 views
2

挨拶良い人。apacheでユーザー名トークンを暗号化するcxf

私は消費したいソープWebサービスを持っています。実際のプロジェクト、特にユーザー名トークンの暗号化に必要なものをシミュレートする小さなプロジェクトを作成しました。

以下に示すように、クライアント側でパスワードを暗号化する方法の提供のステップがあります。

  • は暗号化されていないパスワード値を書き込みます。
  • 次に、手順1で作成したデータのブロックを、パスワードキー証明書の公開部分で暗号化します。 RSAアルゴリズムを使用し、PKCS#1.5のパディング(OAEPではなく)を使用し、結果を暗号化されたストリームに追加します。これはAPIを介して送信される暗号化されたパスワードになります。
  • 結果の暗号化バイト配列を、base64エンコーディングを使用して文字列に変換します。イニシエータのSecurityCredential値としてAPIリクエストにこのbase64でエンコードされた文字列を表示します。
  • この目的のためにイニシエータに発行されたX509証明書から公開鍵で暗号化されるパスワード。

これまでのところ、私はクライアントとサーバーを作成することができ、リクエストを送信して応答を得ることができました。

ClientPasswordCallbackクラスにpasswordというプレーンテキストのユーザー名トークンを渡し、ServerPasswordCallbackクラスのこれらのクレデンシャルをチェックすることで、Webサービスを保護することもできます。

私はさらに行っているとで別々のリクエストがWSS4Jを使用して、メッセージのボディ部を暗号化し、RSAX509私はclientKey.jksに格納されている公開鍵とのPrivateKeyに保存されている秘密鍵を持っていることにより、 .jksを使用し、クライアントとサーバーのパスワードコールバックハンドラで適切なパスワードを提供することで、クライアントで本体部分を暗号化し、サーバーで復号化することができました。

チャレンジ:上記の2つの手順を1回のリクエストで組み合わせると、パブリックキーを使用してユーザー名トークンのパスワードを暗号化し、そのパスワードをサーバー側は秘密鍵を使用します。

NB私は、jdkに付属のkeygenツールを使用してテスト用のキーを生成しました。

ClientPasswordCallbackクラスには、clientKey.jksキーストア用のパスワードと暗号化が必要なその他のパスワードの2つのパスワードがあると思います。

これは私がこれまでにアーカイブすることができたものです:

クライアント側

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

} 

}

サーバ側

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私は春を使用していません。カスタムは、あなたのWebサービスにそれをフックする方法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を暗号化するのではなく、ユーザー名トークンのみを暗号化するようにUsernameTokenに変更する必要があります。それは可能ですか、提案したとおりにプログラムでパスワードを暗号化し、ヘッダーに渡す必要がありますか? – chilopoda

+0

こんにちは、パスワードを平文またはダイジェストとして送信することができます。つまり、一方通しのハッシュを意味します。パスワードを暗号化して解読する必要がある場合は、私の提案する解決策を使用する必要があります。 – Frank

関連する問題