1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.wss4j.dom.validate;
21
22 import java.io.IOException;
23 import java.nio.charset.StandardCharsets;
24 import java.security.MessageDigest;
25
26 import javax.security.auth.callback.Callback;
27 import javax.security.auth.callback.UnsupportedCallbackException;
28
29 import org.apache.wss4j.dom.WSConstants;
30 import org.apache.wss4j.common.ext.WSPasswordCallback;
31 import org.apache.wss4j.common.ext.WSSecurityException;
32 import org.apache.wss4j.common.util.UsernameTokenUtil;
33 import org.apache.wss4j.dom.handler.RequestData;
34 import org.apache.wss4j.dom.message.token.UsernameToken;
35 import org.apache.xml.security.utils.XMLUtils;
36
37
38
39
40
41 public class UsernameTokenValidator implements Validator {
42
43 private static final org.slf4j.Logger LOG =
44 org.slf4j.LoggerFactory.getLogger(UsernameTokenValidator.class);
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public Credential validate(Credential credential, RequestData data) throws WSSecurityException {
61 if (credential == null || credential.getUsernametoken() == null) {
62 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCredential");
63 }
64
65 boolean handleCustomPasswordTypes = data.isHandleCustomPasswordTypes();
66 boolean passwordsAreEncoded = data.isEncodePasswords();
67 String requiredPasswordType = data.getRequiredPasswordType();
68
69 UsernameToken usernameToken = credential.getUsernametoken();
70 usernameToken.setPasswordsAreEncoded(passwordsAreEncoded);
71
72 String pwType = usernameToken.getPasswordType();
73 LOG.debug("UsernameToken user {}", usernameToken.getName());
74 LOG.debug("UsernameToken password type {}", pwType);
75
76 if (requiredPasswordType != null && !requiredPasswordType.equals(pwType)) {
77 LOG.warn("Authentication failed as the received password type does not "
78 + "match the required password type of: {}", requiredPasswordType);
79 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
80 }
81
82
83
84
85
86
87 String password = usernameToken.getPassword();
88 if (usernameToken.isHashed()) {
89 verifyDigestPassword(usernameToken, data);
90 } else if (WSConstants.PASSWORD_TEXT.equals(pwType)
91 || password != null && (pwType == null || pwType.trim().length() == 0)) {
92 verifyPlaintextPassword(usernameToken, data);
93 } else if (password != null) {
94 if (!handleCustomPasswordTypes) {
95 LOG.warn("Authentication failed as handleCustomUsernameTokenTypes is false");
96 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
97 }
98 verifyCustomPassword(usernameToken, data);
99 } else {
100 verifyUnknownPassword(usernameToken, data);
101 }
102 return credential;
103 }
104
105
106
107
108
109
110
111
112
113
114
115 protected void verifyCustomPassword(UsernameToken usernameToken,
116 RequestData data) throws WSSecurityException {
117 verifyPlaintextPassword(usernameToken, data);
118 }
119
120
121
122
123
124
125
126
127
128
129
130 protected void verifyPlaintextPassword(UsernameToken usernameToken,
131 RequestData data) throws WSSecurityException {
132 verifyDigestPassword(usernameToken, data);
133 }
134
135
136
137
138
139
140
141
142 protected void verifyDigestPassword(UsernameToken usernameToken,
143 RequestData data) throws WSSecurityException {
144 if (data.getCallbackHandler() == null) {
145 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCallback");
146 }
147
148 String user = usernameToken.getName();
149 String password = usernameToken.getPassword();
150 String nonce = usernameToken.getNonce();
151 String createdTime = usernameToken.getCreated();
152 String pwType = usernameToken.getPasswordType();
153 boolean passwordsAreEncoded = usernameToken.getPasswordsAreEncoded();
154
155 WSPasswordCallback pwCb =
156 new WSPasswordCallback(user, null, pwType, WSPasswordCallback.USERNAME_TOKEN);
157 try {
158 data.getCallbackHandler().handle(new Callback[]{pwCb});
159 } catch (IOException | UnsupportedCallbackException e) {
160 LOG.debug(e.getMessage(), e);
161 throw new WSSecurityException(
162 WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e
163 );
164 }
165 String origPassword = pwCb.getPassword();
166 if (origPassword == null) {
167 LOG.warn("Callback supplied no password for: {}", user);
168 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
169 }
170 if (usernameToken.isHashed()) {
171 byte[] decodedNonce = XMLUtils.decode(nonce);
172 byte[] decodedPassword = XMLUtils.decode(password);
173 byte[] passDigest;
174 if (passwordsAreEncoded) {
175 passDigest = UsernameTokenUtil.doRawPasswordDigest(decodedNonce, createdTime,
176 XMLUtils.decode(origPassword));
177 } else {
178 passDigest = UsernameTokenUtil.doRawPasswordDigest(decodedNonce, createdTime,
179 origPassword.getBytes(StandardCharsets.UTF_8));
180 }
181 if (!MessageDigest.isEqual(decodedPassword, passDigest)) {
182 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
183 }
184 } else {
185 byte[] origPasswordBytes = origPassword.getBytes(StandardCharsets.UTF_8);
186 byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8);
187 if (!MessageDigest.isEqual(origPasswordBytes, passwordBytes)) {
188 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
189 }
190 }
191 }
192
193
194
195
196
197
198
199 protected void verifyUnknownPassword(UsernameToken usernameToken,
200 RequestData data) throws WSSecurityException {
201
202 boolean allowUsernameTokenDerivedKeys = data.isAllowUsernameTokenNoPassword();
203 if (!allowUsernameTokenDerivedKeys) {
204 LOG.warn("Authentication failed as the received UsernameToken does not "
205 + "contain any password element");
206 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
207 }
208 }
209
210 }