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
024 package microsoft.exchange.webservices.data.credential;
025
026 import microsoft.exchange.webservices.data.core.EwsUtilities;
027
028 import javax.xml.stream.XMLStreamException;
029 import javax.xml.stream.XMLStreamWriter;
030
031 import java.net.URI;
032 import java.net.URISyntaxException;
033 import java.util.Calendar;
034
035 /**
036 * WSSecurityBasedCredentials is the base class for all credential classes using
037 * WS-Security.
038 */
039 public 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 }