1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.impl.processor.output;
20
21 import org.apache.wss4j.common.ext.WSPasswordCallback;
22 import org.apache.wss4j.common.ext.WSSecurityException;
23 import org.apache.wss4j.common.util.DateUtil;
24 import org.apache.wss4j.common.util.UsernameTokenUtil;
25 import org.apache.wss4j.stax.ext.WSSConstants;
26 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
27 import org.apache.wss4j.stax.impl.securityToken.OutboundUsernameSecurityToken;
28 import org.apache.wss4j.stax.utils.WSSUtils;
29 import org.apache.xml.security.exceptions.XMLSecurityException;
30 import org.apache.xml.security.stax.ext.*;
31 import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
32 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
33 import org.apache.xml.security.stax.impl.util.IDGenerator;
34 import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
35 import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
36 import org.apache.xml.security.utils.XMLUtils;
37
38 import javax.security.auth.callback.CallbackHandler;
39 import javax.xml.namespace.QName;
40 import javax.xml.stream.XMLStreamException;
41
42 import java.time.Instant;
43 import java.time.ZoneOffset;
44 import java.util.ArrayList;
45 import java.util.List;
46
47 public class UsernameTokenOutputProcessor extends AbstractOutputProcessor {
48
49 public UsernameTokenOutputProcessor() throws XMLSecurityException {
50 super();
51 addBeforeProcessor(WSSSignatureOutputProcessor.class);
52 addBeforeProcessor(EncryptOutputProcessor.class);
53 }
54
55 @Override
56 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
57 throws XMLStreamException, XMLSecurityException {
58
59 try {
60 CallbackHandler callbackHandler = ((WSSSecurityProperties)getSecurityProperties()).getCallbackHandler();
61 WSSConstants.UsernameTokenPasswordType usernameTokenPasswordType =
62 ((WSSSecurityProperties) getSecurityProperties()).getUsernameTokenPasswordType();
63
64 if (callbackHandler == null
65 && WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE != usernameTokenPasswordType) {
66 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCallback");
67 }
68
69 String password = null;
70 if (callbackHandler != null) {
71 WSPasswordCallback pwCb =
72 new WSPasswordCallback(((WSSSecurityProperties) getSecurityProperties()).getTokenUser(),
73 WSPasswordCallback.USERNAME_TOKEN);
74 WSSUtils.doPasswordCallback(callbackHandler, pwCb);
75 password = pwCb.getPassword();
76 }
77
78 if (password == null && WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE != usernameTokenPasswordType) {
79 final Object[] args = {((WSSSecurityProperties) getSecurityProperties()).getTokenUser() };
80 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noPassword", args);
81 }
82
83 final String wsuId = IDGenerator.generateID(null);
84
85 boolean useDerivedKeyForMAC =
86 ((WSSSecurityProperties)getSecurityProperties()).isUseDerivedKeyForMAC();
87 int derivedIterations =
88 ((WSSSecurityProperties)getSecurityProperties()).getDerivedKeyIterations();
89 byte[] salt = null;
90 if (WSSConstants.USERNAMETOKEN_SIGNED.equals(getAction())) {
91 salt = UsernameTokenUtil.generateSalt(useDerivedKeyForMAC);
92 }
93
94 byte[] nonceValue = null;
95 if (usernameTokenPasswordType == WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST
96 || ((WSSSecurityProperties) getSecurityProperties()).isAddUsernameTokenNonce()) {
97 nonceValue = WSSConstants.generateBytes(16);
98 }
99
100 String createdStr = "";
101 if (usernameTokenPasswordType == WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST
102 || ((WSSSecurityProperties) getSecurityProperties()).isAddUsernameTokenCreated()) {
103 Instant created = Instant.now();
104 createdStr = created.atZone(ZoneOffset.UTC).format(DateUtil.getDateTimeFormatter(true));
105 }
106
107 final OutputProcessor outputProcessor = this;
108
109 final OutboundUsernameSecurityToken usernameSecurityToken =
110 new OutboundUsernameSecurityToken(((WSSSecurityProperties) getSecurityProperties()).getTokenUser(),
111 password,
112 createdStr,
113 nonceValue,
114 wsuId,
115 salt,
116 derivedIterations
117 );
118 usernameSecurityToken.setProcessor(outputProcessor);
119
120 SecurityTokenProvider<OutboundSecurityToken> securityTokenProvider =
121 new SecurityTokenProvider<OutboundSecurityToken>() {
122
123 @Override
124 public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
125 return usernameSecurityToken;
126 }
127
128 @Override
129 public String getId() {
130 return wsuId;
131 }
132 };
133 if (WSSConstants.USERNAMETOKEN_SIGNED.equals(getAction())) {
134 outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(wsuId, securityTokenProvider);
135 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, wsuId);
136 }
137 final FinalUsernameTokenOutputProcessor finalUsernameTokenOutputProcessor =
138 new FinalUsernameTokenOutputProcessor(wsuId, nonceValue, password, createdStr, salt, derivedIterations, getAction());
139 getBeforeProcessors().forEach(finalUsernameTokenOutputProcessor::addBeforeProcessor);
140 finalUsernameTokenOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
141 finalUsernameTokenOutputProcessor.setAction(getAction(), getActionOrder());
142 finalUsernameTokenOutputProcessor.init(outputProcessorChain);
143
144 } finally {
145 outputProcessorChain.removeProcessor(this);
146 }
147 outputProcessorChain.processEvent(xmlSecEvent);
148 }
149
150 static class FinalUsernameTokenOutputProcessor extends AbstractOutputProcessor {
151
152 private String wsuId;
153 private byte[] nonceValue;
154 private String password;
155 private String created;
156 private byte[] salt;
157 private int iterations;
158 private XMLSecurityConstants.Action action;
159
160 FinalUsernameTokenOutputProcessor(String wsuId, byte[] nonceValue, String password,
161 String created, byte[] salt,
162 int iterations, XMLSecurityConstants.Action action)
163 throws XMLSecurityException {
164 super();
165 this.addAfterProcessor(UsernameTokenOutputProcessor.class);
166 this.wsuId = wsuId;
167 this.nonceValue = nonceValue;
168 this.password = password;
169 this.created = created;
170 this.salt = salt;
171 this.iterations = iterations;
172 this.action = action;
173 }
174
175 @Override
176 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
177 throws XMLStreamException, XMLSecurityException {
178
179 outputProcessorChain.processEvent(xmlSecEvent);
180
181 if (WSSUtils.isSecurityHeaderElement(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
182
183 final QName headerElementName = WSSConstants.TAG_WSSE_USERNAME_TOKEN;
184 OutputProcessorUtils.updateSecurityHeaderOrder(outputProcessorChain, headerElementName, getAction(), false);
185
186 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
187
188 List<XMLSecAttribute> attributes = new ArrayList<>(1);
189 attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, this.wsuId));
190 createStartElementAndOutputAsEvent(subOutputProcessorChain, headerElementName, false, attributes);
191 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_USERNAME, false, null);
192 createCharactersAndOutputAsEvent(subOutputProcessorChain,
193 ((WSSSecurityProperties) getSecurityProperties()).getTokenUser());
194 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_USERNAME);
195 if (((WSSSecurityProperties) getSecurityProperties()).getUsernameTokenPasswordType()
196 != WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE && !WSSConstants.USERNAMETOKEN_SIGNED.equals(action)) {
197 attributes = new ArrayList<>(1);
198 attributes.add(createAttribute(WSSConstants.ATT_NULL_Type,
199 ((WSSSecurityProperties) getSecurityProperties()).getUsernameTokenPasswordType()
200 == WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST
201 ? WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST.getNamespace()
202 : WSSConstants.UsernameTokenPasswordType.PASSWORD_TEXT.getNamespace()));
203 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_PASSWORD, false, attributes);
204 createCharactersAndOutputAsEvent(subOutputProcessorChain,
205 ((WSSSecurityProperties) getSecurityProperties()).getUsernameTokenPasswordType()
206 == WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST
207 ? UsernameTokenUtil.doPasswordDigest(this.nonceValue, created, this.password)
208 : this.password);
209 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_PASSWORD);
210 }
211
212 if (salt != null) {
213 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE11_SALT, true, null);
214 createCharactersAndOutputAsEvent(subOutputProcessorChain, XMLUtils.encodeToString(this.salt));
215 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE11_SALT);
216
217 if (iterations > 0) {
218 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE11_ITERATION, true, null);
219 createCharactersAndOutputAsEvent(subOutputProcessorChain, "" + iterations);
220 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE11_ITERATION);
221 }
222 }
223
224 if (nonceValue != null && !WSSConstants.USERNAMETOKEN_SIGNED.equals(action)) {
225 attributes = new ArrayList<>(1);
226 attributes.add(createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE, WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
227 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_NONCE, false, attributes);
228 createCharactersAndOutputAsEvent(subOutputProcessorChain,
229 XMLUtils.encodeToString(this.nonceValue));
230 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_NONCE);
231 }
232
233 if (created != null && created.length() != 0) {
234 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSU_CREATED, false, null);
235 createCharactersAndOutputAsEvent(subOutputProcessorChain, created);
236 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSU_CREATED);
237 }
238
239 createEndElementAndOutputAsEvent(subOutputProcessorChain, headerElementName);
240
241 outputProcessorChain.removeProcessor(this);
242 }
243 }
244 }
245 }