1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.stax.validate;
20
21 import java.nio.charset.StandardCharsets;
22 import java.security.MessageDigest;
23
24 import org.apache.wss4j.binding.wss10.AttributedString;
25 import org.apache.wss4j.binding.wss10.EncodedString;
26 import org.apache.wss4j.binding.wss10.PasswordString;
27 import org.apache.wss4j.binding.wss10.UsernameTokenType;
28 import org.apache.wss4j.binding.wsu10.AttributedDateTime;
29 import org.apache.wss4j.common.ext.WSPasswordCallback;
30 import org.apache.wss4j.common.ext.WSSecurityException;
31 import org.apache.wss4j.common.util.UsernameTokenUtil;
32 import org.apache.wss4j.stax.ext.WSSConstants;
33 import org.apache.wss4j.stax.securityToken.UsernameSecurityToken;
34 import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
35 import org.apache.wss4j.stax.utils.WSSUtils;
36 import org.apache.wss4j.stax.impl.securityToken.UsernameSecurityTokenImpl;
37 import org.apache.xml.security.stax.ext.XMLSecurityUtils;
38 import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
39 import org.apache.xml.security.utils.XMLUtils;
40
41 public class UsernameTokenValidatorImpl implements UsernameTokenValidator {
42
43 private static final transient org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(UsernameTokenValidatorImpl.class);
44
45 @Override
46 public <T extends UsernameSecurityToken & InboundSecurityToken> T validate(
47 UsernameTokenType usernameTokenType, TokenContext tokenContext) throws WSSecurityException {
48
49
50
51
52 final byte[] salt = XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE11_SALT);
53 PasswordString passwordType = XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE_PASSWORD);
54 final Long iteration = XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE11_ITERATION);
55 if (salt != null && (passwordType != null || iteration == null)) {
56 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "badTokenType01");
57 }
58
59 boolean handleCustomPasswordTypes = tokenContext.getWssSecurityProperties().getHandleCustomPasswordTypes();
60 boolean allowUsernameTokenNoPassword =
61 tokenContext.getWssSecurityProperties().isAllowUsernameTokenNoPassword()
62 || Boolean.parseBoolean((String)tokenContext.getWsSecurityContext().get(WSSConstants.PROP_ALLOW_USERNAMETOKEN_NOPASSWORD));
63
64
65 WSSConstants.UsernameTokenPasswordType requiredPasswordType =
66 tokenContext.getWssSecurityProperties().getUsernameTokenPasswordType();
67 if (requiredPasswordType != null) {
68 if (passwordType == null || passwordType.getType() == null) {
69 LOG.warn("Authentication failed as the received password type does not "
70 + "match the required password type of: {}", requiredPasswordType);
71 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
72 }
73 WSSConstants.UsernameTokenPasswordType usernameTokenPasswordType =
74 WSSConstants.UsernameTokenPasswordType.getUsernameTokenPasswordType(passwordType.getType());
75 if (requiredPasswordType != usernameTokenPasswordType) {
76 LOG.warn("Authentication failed as the received password type does not "
77 + "match the required password type of: {}", requiredPasswordType);
78 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
79 }
80 }
81
82 WSSConstants.UsernameTokenPasswordType usernameTokenPasswordType = WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE;
83 if (passwordType != null && passwordType.getType() != null) {
84 usernameTokenPasswordType = WSSConstants.UsernameTokenPasswordType.getUsernameTokenPasswordType(passwordType.getType());
85 }
86
87 final AttributedString username = usernameTokenType.getUsername();
88 if (username == null) {
89 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "badTokenType01");
90 }
91
92 final EncodedString encodedNonce =
93 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSSE_NONCE);
94 byte[] nonceVal = null;
95 if (encodedNonce != null && encodedNonce.getValue() != null) {
96 nonceVal = XMLUtils.decode(encodedNonce.getValue());
97 }
98
99 final AttributedDateTime attributedDateTimeCreated =
100 XMLSecurityUtils.getQNameType(usernameTokenType.getAny(), WSSConstants.TAG_WSU_CREATED);
101
102 String created = null;
103 if (attributedDateTimeCreated != null) {
104 created = attributedDateTimeCreated.getValue();
105 }
106
107 if (usernameTokenPasswordType == WSSConstants.UsernameTokenPasswordType.PASSWORD_DIGEST) {
108 if (encodedNonce == null || attributedDateTimeCreated == null) {
109 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN, "badTokenType01");
110 }
111
112 if (!WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING.equals(encodedNonce.getEncodingType())) {
113 throw new WSSecurityException(WSSecurityException.ErrorCode.UNSUPPORTED_SECURITY_TOKEN, "badTokenType01");
114 }
115
116 verifyDigestPassword(username.getValue(), passwordType, nonceVal, created, tokenContext);
117 } else if (usernameTokenPasswordType == WSSConstants.UsernameTokenPasswordType.PASSWORD_TEXT
118 || passwordType != null && passwordType.getValue() != null
119 && usernameTokenPasswordType == WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE) {
120
121 verifyPlaintextPassword(username.getValue(), passwordType, tokenContext);
122 } else if (passwordType != null && passwordType.getValue() != null) {
123 if (!handleCustomPasswordTypes) {
124 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
125 }
126 verifyCustomPassword(username.getValue(), passwordType, tokenContext);
127 } else {
128 if (!allowUsernameTokenNoPassword) {
129 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
130 }
131 }
132
133 final String password;
134 if (passwordType != null) {
135 password = passwordType.getValue();
136 } else if (salt != null) {
137 WSPasswordCallback pwCb = new WSPasswordCallback(username.getValue(),
138 WSPasswordCallback.USERNAME_TOKEN);
139 try {
140 WSSUtils.doPasswordCallback(tokenContext.getWssSecurityProperties().getCallbackHandler(), pwCb);
141 } catch (WSSecurityException e) {
142 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e);
143 }
144 password = pwCb.getPassword();
145 } else {
146 password = null;
147 }
148
149 UsernameSecurityTokenImpl usernameSecurityToken = new UsernameSecurityTokenImpl(
150 usernameTokenPasswordType, username.getValue(), password, created,
151 nonceVal, salt, iteration,
152 tokenContext.getWsSecurityContext(), usernameTokenType.getId(),
153 WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE);
154 usernameSecurityToken.setElementPath(tokenContext.getElementPath());
155 usernameSecurityToken.setXMLSecEvent(tokenContext.getFirstXMLSecEvent());
156
157 @SuppressWarnings("unchecked")
158 T token = (T)usernameSecurityToken;
159 return token;
160 }
161
162
163
164
165 protected void verifyDigestPassword(
166 String username,
167 PasswordString passwordType,
168 byte[] nonceVal,
169 String created,
170 TokenContext tokenContext
171 ) throws WSSecurityException {
172 WSPasswordCallback pwCb = new WSPasswordCallback(username,
173 null,
174 passwordType.getType(),
175 WSPasswordCallback.USERNAME_TOKEN);
176 try {
177 WSSUtils.doPasswordCallback(tokenContext.getWssSecurityProperties().getCallbackHandler(), pwCb);
178 } catch (WSSecurityException e) {
179 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e);
180 }
181
182 if (pwCb.getPassword() == null) {
183 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
184 }
185
186 byte[] passDigest = UsernameTokenUtil.doRawPasswordDigest(nonceVal, created,
187 pwCb.getPassword().getBytes(StandardCharsets.UTF_8));
188 byte[] decodedPassword = XMLUtils.decode(passwordType.getValue());
189 if (!MessageDigest.isEqual(decodedPassword, passDigest)) {
190 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
191 }
192 passwordType.setValue(pwCb.getPassword());
193 }
194
195
196
197
198 protected void verifyPlaintextPassword(
199 String username,
200 PasswordString passwordType,
201 TokenContext tokenContext
202 ) throws WSSecurityException {
203 WSPasswordCallback pwCb = new WSPasswordCallback(username,
204 null,
205 passwordType.getType(),
206 WSPasswordCallback.USERNAME_TOKEN);
207 try {
208 WSSUtils.doPasswordCallback(tokenContext.getWssSecurityProperties().getCallbackHandler(), pwCb);
209 } catch (WSSecurityException e) {
210 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e);
211 }
212
213 if (pwCb.getPassword() == null) {
214 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
215 }
216
217 byte[] origPasswordBytes = pwCb.getPassword().getBytes(StandardCharsets.UTF_8);
218 byte[] passwordBytes = passwordType.getValue().getBytes(StandardCharsets.UTF_8);
219 if (!MessageDigest.isEqual(origPasswordBytes, passwordBytes)) {
220 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
221 }
222 passwordType.setValue(pwCb.getPassword());
223 }
224
225
226
227
228
229 protected void verifyCustomPassword(
230 String username,
231 PasswordString passwordType,
232 TokenContext tokenContext
233 ) throws WSSecurityException {
234 verifyPlaintextPassword(username, passwordType, tokenContext);
235 }
236 }