홈>
Java 코드를 통해 HTTPS SOAP 웹 서비스를 호출하려고합니다 :
URL url = new URL("https://somehost:8181/services/"SomeService?wsdl");
QName qname = new QName("http://services.somehost.com/", "SomeService");
Service service = Service.create(url, qname);
SomeService port = service.getPort(SomeService .class);
port.doSomething();
그러나 예외가 발생합니다 :
threw an unexpected exception: javax.xml.ws.soap.SOAPFaultException: Security Requirements not met - No Security header in message
올바른 요청 샘플을 분석 할 때 헤더를 포함해야한다고 결정했습니다 :
<S:Header>
<To xmlns="http://www.w3.org/2005/08/addressing">http://somehost:8181/services/SomeService</To>
<Action xmlns="http://www.w3.org/2005/08/addressing">https://somehost:8181/services/"SomeService/doSomethingRequest</Action>
<ReplyTo xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
<MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:3428539e-d645-72ae-adc0-5423c1e68942</MessageID>
<wsse:Security S:mustUnderstand="true">
<wsu:Timestamp wsu:Id="_1" xmlns:ns14="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns13="http://schemas.xmlsoap.org/soap/envelope/">
<wsu:Created>2013-01-15T16:36:30Z</wsu:Created>
<wsu:Expires>2014-01-15T14:06:30Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
SOAP 요청에이 헤더를 추가하는 방법은 무엇입니까?
- 답변 # 1
- 답변 # 2
@LaabidiRaissi에서 언급 한 단계를 수행했습니다. 코드는 정상적으로 작동하지만 헤더 아래에 보안 요소를 추가하지 않습니다. 아웃 바운드 SOAP 메시지를 System.out에 인쇄하여 확인했습니다. 심도있는 조사를 거친 후 업데이트 된 메시지 헤더를 반영하기 위해 SOAPMessage를 명시 적으로 저장해야한다는 것을 알았습니다.
soapMessage.saveChanges();
자세한 내용은- 이 링크를 확인
- 답변 # 3
Apache wss4j를 사용하여 헤더를 쉽게 추가하고 비밀번호를 암호화 할 수도 있습니다.
import org.apache.ws.security.WSConstants; import org.apache.ws.security.message.WSSecHeader; import org.apache.ws.security.message.WSSecUsernameToken; import javax.xml.namespace.QName; import javax.xml.soap.SOAPMessage; import javax.xml.soap.SOAPPart; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import java.io.ByteArrayOutputStream; import java.util.Set; public class WSSecurityHeaderSOAPHandler implements SOAPHandler<SOAPMessageContext> { private final String usernameText; private final String passwordText; public WSSecurityHeaderSOAPHandler(String usernameText, String passwordText) { this.usernameText = usernameText; this.passwordText = passwordText; } @Override public boolean handleMessage(SOAPMessageContext context) { Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outboundProperty.booleanValue()) { try { SOAPMessage soapMessage = context.getMessage(); soapMessage.removeAllAttachments(); SOAPPart soappart = soapMessage.getSOAPPart(); WSSecHeader wsSecHeader = new WSSecHeader(); wsSecHeader.insertSecurityHeader(soappart); WSSecUsernameToken token = new WSSecUsernameToken(); token.setPasswordType(WSConstants.PASSWORD_DIGEST); token.setUserInfo(usernameText, passwordText); token.build(soappart, wsSecHeader); soapMessage.saveChanges(); } catch (Exception e) { throw new RuntimeException("Error on wsSecurityHandler: " + e.getMessage()); } } return true; } @Override public boolean handleFault(SOAPMessageContext context) { return false; } @Override public void close(MessageContext context) { } @Override public Set<QName> getHeaders() { return null; } }
그리고 다음과 같이 요청을 업데이트해야합니다 :
// This is the block that apply the Ws Security to the request BindingProvider bindingProvider = (BindingProvider) portType; List<Handler> handlerChain = new ArrayList<>(); handlerChain.add(new WSSecurityHeaderSOAPHandler("username", "password")); bindingProvider.getBinding().setHandlerChain(handlerChain);
Maven 종속성 :
<dependency> <groupId>org.apache.ws.security</groupId> <artifactId>wss4j</artifactId> <version>1.6.19</version> </dependency>
- 답변 # 4
샘플 메인 클래스 :
package test; import java.util.ArrayList; import java.util.List; import javax.xml.ws.BindingProvider; import javax.xml.ws.handler.Handler; // next headers is generated from "NetBeans New Webservice Client" import sk.firma.wstest.definitions.*; import sk.firma.wstest.schemas.*; /** * * @author Jan */ public class TestWSService { /** * @param args the command line arguments */ public static void main(String[] args) { try { WsService service = new WsService(); Ws port = service.getWsKsSoap11(); // This is the block that apply the Ws Security to the request BindingProvider bindingProvider = (BindingProvider) port; @SuppressWarnings("rawtypes") List<Handler> handlerChain = new ArrayList<Handler>(); handlerChain.add(new WSSecurityHeaderSOAPHandler("username", "password")); bindingProvider.getBinding().setHandlerChain(handlerChain); // Initialize and Run Service InVal inVal = new InVal(); ReturnValue retVal = port.test(inVal); } catch (Exception e) { e.printStackTrace(); } } }
이제 WS-Security 헤더 SOAP 핸들러 :
package test; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import java.util.Set; import java.util.TimeZone; import javax.xml.namespace.QName; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPEnvelope; import javax.xml.soap.SOAPHeader; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; public class WSSecurityHeaderSOAPHandler implements SOAPHandler<SOAPMessageContext> { private static final String URL_WSSE_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; private static final String URL_WSU_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"; private final String usernameText; private final String passwordText; public WSSecurityHeaderSOAPHandler(String usernameText, String passwordText) { this.usernameText = usernameText; this.passwordText = passwordText; } public String getCurrentDateTime() { /* e.g. 2001-10-13T09:00:00Z */ final SimpleDateFormat FORMATTER_DATETIME_NO_MS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); DateFormat dfETC = FORMATTER_DATETIME_NO_MS; dfETC.setTimeZone(TimeZone.getTimeZone("CET")); StringBuffer dateETC = new StringBuffer(dfETC.format(new Date())); dateETC.append('Z'); return dateETC.toString(); } public String getCurrentDateTimePlusDelay(long delayInSeconds) { /* e.g. 2001-10-13T09:00:00Z */ final SimpleDateFormat FORMATTER_DATETIME_NO_MS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); DateFormat dfETC = FORMATTER_DATETIME_NO_MS; dfETC.setTimeZone(TimeZone.getTimeZone("CET")); Date date = new Date(); long timeInMsecs = date.getTime(); date.setTime(timeInMsecs + delayInSeconds*1000L); StringBuffer dateETC = new StringBuffer(dfETC.format(date)); dateETC.append('Z'); return dateETC.toString(); } @Override public boolean handleMessage(SOAPMessageContext soapMessageContext) { Boolean outboundProperty = (Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outboundProperty) { try { SOAPEnvelope soapEnvelope = soapMessageContext.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = soapEnvelope.getHeader(); if (header == null) { header = soapEnvelope.addHeader(); } SOAPElement securityHeaderElement = header.addChildElement("Security", "wsse", URL_WSSE_NAMESPACE); securityHeaderElement.addAttribute(soapEnvelope.createName("S:mustUnderstand"), "1"); // Add Timestamp element to "Security" soapHeaderElement // Sample: <u:Timestamp> // <u:Created>2011-10-13T08:20:01.183Z</u:Created> // <u:Expires>2011-10-13T17:25:01.183Z</u:Expires> // </u:Timestamp> javax.xml.soap.Name timestampElementName = soapEnvelope.createName("Timestamp", "wsu", URL_WSU_NAMESPACE); SOAPElement timestampSOAPElement = securityHeaderElement.addChildElement(timestampElementName); String created = getCurrentDateTime(); String expires = getCurrentDateTimePlusDelay(60L*60L); /* 60 minutes delay */ // Add Created to Timestamp SOAPElement createdSOAPElement = timestampSOAPElement .addChildElement("Created"/* local name */, "wsu" /* prefix */, URL_WSU_NAMESPACE); createdSOAPElement.addTextNode(created); // Add Expires to Timestamp SOAPElement expiresSOAPElement = timestampSOAPElement .addChildElement("Expires"/* local name */, "wsu" /* prefix */,URL_WSU_NAMESPACE); expiresSOAPElement.addTextNode(expires); // Add usernameToken to "Security" soapHeaderElement javax.xml.soap.Name usernameTokenElementName = soapEnvelope.createName("UsernameToken", "wsse", URL_WSSE_NAMESPACE); SOAPElement usernameTokenSOAPElement = securityHeaderElement.addChildElement(usernameTokenElementName); // Add Username to usernameToken SOAPElement userNameSOAPElement = usernameTokenSOAPElement .addChildElement("Username"/* local name */, "wsse" /* prefix */, URL_WSSE_NAMESPACE); userNameSOAPElement.addTextNode(this.usernameText); // Add password to UsernameToken javax.xml.soap.Name passwordElementName = soapEnvelope.createName("Password", "wsse", URL_WSSE_NAMESPACE); SOAPElement passwordSOAPElement = usernameTokenSOAPElement.addChildElement(passwordElementName); /* Add "Type" attribute to <Password> header element */ //passwordSOAPElement.addAttribute(soapEnvelope.createName("Type", "", ""), // "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText"); passwordSOAPElement.addTextNode(this.passwordText); } catch (Exception e) { throw new RuntimeException("Error on wsSecurityHandler: " + e.getMessage()); } } return true; } @Override public void close(MessageContext context) { // TODO Auto-generated method stub } @Override public boolean handleFault(SOAPMessageContext context) { // TODO Auto-generated method stub return true; } @Override public Set<QName> getHeaders() { // throw new UnsupportedOperationException("Not supported yet."); final QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "wsse"); final HashSet headers = new HashSet(); headers.add(securityHeader); return headers; } }
관련 자료
- javascript - discordjs v12 - 역할을 추가하는 방법은 무엇입니까?
- C #을 통해 PFX 인증서로 SOAP 요청 보내기
- javascript - Vue 3 사용 및 플러그인 Boostrap-vue 추가 방법?
- c# - httpclient GET 요청에 콘텐츠 유형 헤더 추가
- r 제목으로 열 이름을 추가하는 방법
- big sur - Big Sur Finder 툴바에 앱을 추가하는 방법은 무엇입니까?
- python - 하이펜을 추가하려면 어떻게해야합니까?
- updates - apt-key가 더 이상 사용되지 않으므로 repo gpg 키를 어떻게 추가합니까?
- r - 3D 배열에 요소를 추가하는 방법은 무엇입니까?
- 파이썬에 버튼을 추가하는 방법
- flutter - API에 어떻게 요청할 수 있습니까?
- r - ggplot2에서 얼굴 라벨을 추가하는 방법
- javascript - Object Vuejs에 새 개체를 추가하는 방법
- flutter - [Dart]와 같이 목록에 데이터를 동적으로 추가하려면 어떻게해야합니까?
- python - 두 개의 테이블을 하나로 추가하려면 어떻게해야합니까?
- r - 라인 플롯에 자동화 된 데이터 레이블을 추가하는 방법은 무엇입니까?
- r - col 이름 위에 var 레이블을 추가하는 방법
- c# - WPF 프로젝트에 XamlHost를 추가하는 방법은 무엇입니까?
- android - Gradle로 APK 이름에 MD5를 추가하는 방법
- rest - 파일 다운로드 요청을 어떻게 찾습니까?
개인적으로 HeaderHandler와 HeaderHandlerResolver의 두 클래스를 추가합니다 :
그리고
HeaderHandler 클래스에서 필요한 자격 증명을 추가 할 수 있습니다. 마지막으로 사용하려면 :