У меня есть сборка webservice в PHP, которая использует UsernameToken как механизм аутентификации. У меня есть код на стороне клиента PHP, который может получить доступ к этой веб-службе. Теперь мне нужно сделать это на Java. Возможно ты можешь помочь мне!
Доступ к этой услуге можно получить с помощью следующего кода php:
$password="super_secure_pass"; $timestamp=gmdate('Ymd\TH:i:s\Z'); $nonce=mt_rand(); $passdigest=base64_encode(pack('H*',sha1(pack('H*',$nonce).pack('a*',$timestamp).pack('a*',$password)))); $nonce=base64_encode(pack('H*',$nonce))
Эти значения анализируются в этом заголовке Soap.
<wsse:Security SOAP-ENV:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>'.$username.'</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$passdigest.'</wsse:Password> <wsse:Nonce>'.$nonce.'</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">'.$timestamp.'</wsu:Created> </wsse:UsernameToken> </wsse:Security>
С помощью этого кода я могу без проблем получить доступ к веб-сервису. Теперь мне нужно сделать это на Java.
Я создал необходимые файлы, реализовал обработчик для добавления заголовка мыла с помощью UsernameToken. Но когда я пытаюсь получить доступ к WS, я всегда получаю сообщение об ошибке «Не авторизовано». Я думаю, что я что-то упустил, создав запись passdigest или nonce.
Вот как я их вычисляю:
Random generator = new Random(); String nonceString = String.valueOf(generator.nextInt(999999999)); String createTime=localToGmtTimestamp();//Returns a date with format (SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")) String pass="super_secure_pass"; String tmp = AeSimpleSHA1.SHA1(nonce + createTime + pass); encodedPass = Base64.encodeBytes(tmp.getBytes());
Эти значения будут использоваться при создании заголовка мыла:
SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.addHeader(); SOAPElement security = header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse"); SOAPElement username = usernameToken.addChildElement("Username", "wsse"); username.addTextNode(user); SOAPElement password = usernameToken.addChildElement("Password", "wsse"); password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"); password.addTextNode(encodedPass); SOAPElement nonce = usernameToken.addChildElement("Nonce", "wsse"); nonce.addTextNode(Base64.encodeBytes(nonceString.getBytes())); SOAPElement created = usernameToken.addChildElement("Created", "wsu","http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"); created.addTextNode(creatTime);
Вот как выглядит получившийся заголовок мыла:
<S:Header> <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>myusername</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">ZDM4MjkwNzNlNTc3MjNmMTY4MjgyYWQ1ZjllN2JlZmJmNGY2NDE4MA==</wsse:Password> <wsse:Nonce>NTU5NzA2Mjkw</wsse:Nonce> <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2011-07-24T11:41:55Z</wsu:Created> </wsse:UsernameToken> </wsse:Security> </S:Header>
Кто-нибудь видит, что я делаю неправильно?
Я нашел решение. Моя проблема заключалась в том, что я забыл добавить шестнадцатеричный код в значение NONCE и в удержанную строку. Вот мое решение, возможно, кому-то это нужно.
Функции для создания прохода и т. Д .:
private String calculatePasswordDigest(String nonce, String created, String password) { String encoded = null; try { String pass = hexEncode(nonce) + created + password; MessageDigest md = MessageDigest.getInstance( "SHA1" ); md.update( pass.getBytes() ); byte[] encodedPassword = md.digest(); encoded = Base64.encodeBytes(encodedPassword); } catch (NoSuchAlgorithmException ex) { Logger.getLogger(HeaderHandler.class.getName()).log(Level.SEVERE, null, ex); } return encoded; } private String hexEncode(String in) { StringBuilder sb = new StringBuilder(""); for (int i = 0; i < (in.length() - 2) + 1; i = i + 2) { int c = Integer.parseInt(in.substring(i, i + 2), 16); char chr = (char) c; sb.append(chr); } return sb.toString(); }
Код для создания мыльного сообщения:
String timestamp = HeaderHandler.localToGmtTimestamp(); String pass = "password"; String user = "username"; String nonceString = getNonce(); String dig=calculatePasswordDigest(nonceString, timestamp, pass); SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope(); SOAPHeader header = envelope.addHeader(); SOAPElement security = header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); SOAPElement usernameToken = security.addChildElement("UsernameToken", "wsse"); SOAPElement username = usernameToken.addChildElement("Username", "wsse"); username.addTextNode(user); SOAPElement password = usernameToken.addChildElement("Password", "wsse"); password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"); password.addTextNode(dig); SOAPElement nonce = usernameToken.addChildElement("Nonce", "wsse"); nonce.addTextNode(Base64.encodeBytes(hexEncode(nonceString).getBytes())); SOAPElement created = usernameToken.addChildElement("Created", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"); created.addTextNode(timestamp);