안녕하십니까.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
을 무시할 수 소화 갖고 싶어
안녕 프랭크, 당신의 시간 및 입력 주셔서 감사합니다. 공개 키를 사용하여 암호를 암호화하고 싶습니다. 나는 클라이언트 코드에서 이와 같은 일을하기를 고대하고있다 :'props.put (WSHandlerConstants.ENCRYPTION_PARTS, "{Content} {http://schemas.xmlsoap.org/soap/envelope/} Body"), ' – chilopoda
하지만 Body를 암호화하는 대신 UserNameKoken 부분 만 암호화되도록 UsernameToken으로 변경해야합니다. 가능한가요 아니면 암호로 제안한대로 암호를 암호화 한 다음 헤더에 전달해야합니까? – chilopoda
안녕하세요, 암호를 일반 텍스트 또는 다이제스트로 보낼 수 있습니다. 이는 한쪽으로 해시되었음을 의미합니다. 암호를 암호화하고 암호를 해독해야하는 경우 내 제안 솔루션을 사용해야합니다. – Frank