001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.credential; 025 026import microsoft.exchange.webservices.data.core.EwsUtilities; 027 028import javax.xml.stream.XMLStreamException; 029import javax.xml.stream.XMLStreamWriter; 030 031import java.net.URI; 032import java.net.URISyntaxException; 033import java.util.Calendar; 034 035/** 036 * WSSecurityBasedCredentials is the base class for all credential classes using 037 * WS-Security. 038 */ 039public abstract class WSSecurityBasedCredentials extends ExchangeCredentials { 040 041 /** 042 * The security token. 043 */ 044 private String securityToken; 045 046 /** 047 * The ews url. 048 */ 049 private URI ewsUrl; 050 051 protected static final String wsuTimeStampFormat = 052 "<wsu:Timestamp>" + 053 "<wsu:Created>{0:yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'}</wsu:Created>" + 054 "<wsu:Expires>{1:yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'}</wsu:Expires>" + 055 "</wsu:Timestamp>"; 056 //kavi-start 057 // WS-Security SecExt 1.0 Namespace (and the namespace prefix we will use 058 // for it). 059 /** The Constant WSSecuritySecExt10NamespacePrefix. */ 060 //protected static final String WSSecuritySecExt10NamespacePrefix = "wsse"; 061 062 /** The Constant WSSecuritySecExt10Namespace. */ 063 //protected static final String WSSecuritySecExt10Namespace = 064 // "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; 065 066 // WS-Addressing 1.0 Namespace (and the namespace prefix we will use for 067 // it). 068 069 070 /** The Constant WSAddressing10NamespacePrefix. */ 071 //protected static final String WSAddressing10NamespacePrefix = "wsa"; 072 073 /** The Constant WSAddressing10Namespace. */ 074 //protected static final String WSAddressing10Namespace = 075 // "http://www.w3.org/2005/08/addressing"; 076 077 //kavi end 078 079 // The WS-Addressing headers format string to use for adding the 080 // WS-Addressing headers. 081 // Fill-Ins: %s = Web method name; %s = EWS URL 082 /** 083 * The Constant WsAddressingHeadersFormat. 084 */ 085 protected static final String wsAddressingHeadersFormat = 086 "<wsa:Action soap:mustUnderstand='1'>http://schemas.microsoft.com/exchange/services/2006/messages/%s</wsa:Action>" 087 + 088 "<wsa:ReplyTo><wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>" + 089 "</wsa:ReplyTo>" + 090 "<wsa:To soap:mustUnderstand='1'>%s</wsa:To>"; 091 092 // The WS-Security header format string to use for adding the WS-Security 093 // header. 094 // Fill-Ins: 095 // %s = EncryptedData block (the token) 096 /** 097 * The Constant WsSecurityHeaderFormat. 098 */ 099 protected static final String wsSecurityHeaderFormat = 100 "<wsse:Security soap:mustUnderstand='1'>" + 101 " %s" + // EncryptedData (token) 102 "</wsse:Security>"; 103 104 private boolean addTimestamp; 105 106 // / Path suffix for WS-Security endpoint. 107 /** 108 * The Constant WsSecurityPathSuffix. 109 */ 110 protected static final String wsSecurityPathSuffix = "/wssecurity"; 111 112 /** 113 * Initializes a new instance of the WSSecurityBasedCredentials class. 114 */ 115 protected WSSecurityBasedCredentials() { 116 } 117 118 /** 119 * Initializes a new instance of the WSSecurityBasedCredentials class. 120 * 121 * @param securityToken The security token. 122 */ 123 protected WSSecurityBasedCredentials(String securityToken) { 124 this.securityToken = securityToken; 125 } 126 127 /** 128 * Initializes a new instance of the WSSecurityBasedCredentials class. 129 * 130 * @param securityToken The security token. 131 * @param addTimestamp Timestamp should be added. 132 */ 133 protected WSSecurityBasedCredentials(String securityToken, boolean addTimestamp) { 134 this.securityToken = securityToken; 135 this.addTimestamp = addTimestamp; 136 } 137 138 /** 139 * This method is called to pre-authenticate credential before a service 140 * request is made. 141 */ 142 @Override public void preAuthenticate() { 143 // Nothing special to do here. 144 } 145 146 /** 147 * Emit the extra namespace aliases used for WS-Security and WS-Addressing. 148 * 149 * @param writer the writer 150 * @throws XMLStreamException the XML stream exception 151 */ 152 @Override public void emitExtraSoapHeaderNamespaceAliases(XMLStreamWriter writer) 153 throws XMLStreamException { 154 writer.writeAttribute( 155 "xmlns", 156 "", 157 EwsUtilities.WSSecuritySecExtNamespacePrefix, 158 EwsUtilities.WSSecuritySecExtNamespace); 159 writer.writeAttribute( 160 "xmlns", 161 "", 162 EwsUtilities.WSAddressingNamespacePrefix, 163 EwsUtilities.WSAddressingNamespace); 164 } 165 166 /** 167 * Serialize the WS-Security and WS-Addressing SOAP headers. 168 * 169 * @param writer the writer 170 * @param webMethodName the Web method being called 171 * @throws XMLStreamException the XML stream exception 172 */ 173 @Override public void serializeExtraSoapHeaders(XMLStreamWriter writer, String webMethodName) throws XMLStreamException { 174 this.serializeWSAddressingHeaders(writer, webMethodName); 175 this.serializeWSSecurityHeaders(writer); 176 } 177 178 /** 179 * Creates the WS-Addressing headers necessary to send with an outgoing request. 180 * 181 * @param xmlWriter the XML writer to serialize the headers to 182 * @param webMethodName the Web method being called 183 * @throws XMLStreamException the XML stream exception 184 */ 185 private void serializeWSAddressingHeaders(XMLStreamWriter xmlWriter, 186 String webMethodName) throws XMLStreamException { 187 EwsUtilities.ewsAssert(webMethodName != null, 188 "WSSecurityBasedCredentials.SerializeWSAddressingHeaders", 189 "Web method name cannot be null!"); 190 191 EwsUtilities.ewsAssert(this.ewsUrl != null, 192 "WSSecurityBasedCredentials.SerializeWSAddressingHeaders", 193 "EWS Url cannot be null!"); 194 195 // Format the WS-Addressing headers. 196 String wsAddressingHeaders = String.format( 197 WSSecurityBasedCredentials.wsAddressingHeadersFormat, 198 webMethodName, this.ewsUrl); 199 200 // And write them out... 201 xmlWriter.writeCharacters(wsAddressingHeaders); 202 } 203 204 /** 205 * Creates the WS-Security header necessary to send with an outgoing request. 206 * 207 * @param xmlWriter The XML writer to serialize the headers to 208 * @throws XMLStreamException the XML stream exception 209 */ 210 @Override public void serializeWSSecurityHeaders(XMLStreamWriter xmlWriter) 211 throws XMLStreamException { 212 EwsUtilities.ewsAssert(this.securityToken != null, 213 "WSSecurityBasedCredentials.SerializeWSSecurityHeaders", 214 "Security token cannot be null!"); 215 216 // <wsu:Timestamp wsu:Id="_timestamp"> 217 // <wsu:Created>2007-09-20T01:13:10.468Z</wsu:Created> 218 // <wsu:Expires>2007-09-20T01:18:10.468Z</wsu:Expires> 219 // </wsu:Timestamp> 220 // 221 String timestamp = null; 222 if (this.addTimestamp) { 223 Calendar utcNow = Calendar.getInstance(); 224 utcNow.add(Calendar.MINUTE, 5); 225 timestamp = String.format(WSSecurityBasedCredentials.wsuTimeStampFormat, utcNow, utcNow); 226 227 } 228 229 // Format the WS-Security header based on all the information we have. 230 String wsSecurityHeader = String.format( 231 WSSecurityBasedCredentials.wsSecurityHeaderFormat, 232 timestamp + this.securityToken); 233 234 // And write the header out... 235 xmlWriter.writeCharacters(wsSecurityHeader); 236 } 237 238 /** 239 * Adjusts the URL based on the credential. 240 * 241 * @param url The URL. 242 * @return Adjust URL. 243 * @throws java.net.URISyntaxException the uRI syntax exception 244 */ 245 @Override public URI adjustUrl(URI url) throws URISyntaxException { 246 return new URI(getUriWithoutWSSecurity(url) + WSSecurityBasedCredentials.wsSecurityPathSuffix); 247 } 248 249 /** 250 * Gets the security token. 251 */ 252 protected String getSecurityToken() { 253 return this.securityToken; 254 } 255 256 /** 257 * Sets the security token. 258 */ 259 protected void setSecurityToken(String value) { 260 securityToken = value; 261 } 262 263 /** 264 * Gets the EWS URL. 265 */ 266 protected URI getEwsUrl() { 267 return this.ewsUrl; 268 } 269 270 /** 271 * Sets the EWS URL. 272 */ 273 protected void setEwsUrl(URI value) { 274 ewsUrl = value; 275 } 276}