Walmart.io authentication issue - Could not authenticate in-request, auth signature in C# - walmart-api

I am trying to implement for C#, here is my code:
WebClient downloader = new WebClient();
downloader.Headers["WM_CONSUMER.ID"] = consumerId;
long intimestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
downloader.Headers["WM_CONSUMER.INTIMESTAMP"] = intimestamp.ToString();
downloader.Headers["WM_SEC.KEY_VERSION"] = priviateKeyVersion;
string data = downloader.Headers["WM_CONSUMER.ID"] + "\n" + downloader.Headers["WM_CONSUMER.INTIMESTAMP"] + "\n" + downloader.Headers["WM_SEC.KEY_VERSION"] + "\n";
downloader.Headers["WM_SEC.WM_SEC.AUTH_SIGNATURE"] = getWalmartSig(data);
url = "https://developer.api.walmart.com/api-proxy/service/affil/product/v2/items/" + id;
string json = downloader.DownloadString(url);
to get signature, I use BouncyCastle
private string getWalmartSig(string data)
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"key.pem"))
{ // file containing RSA PKCS1 private key
keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
RSAParameters rsaParam = DotNetUtilities.ToRSAParameters((RsaKeyParameters)keyPair.Public);
ISigner signer = SignerUtilities.GetSigner("SHA256WithRSA");
signer.Init(true, keyPair.Private);
byte[] msg = Encoding.UTF8.GetBytes(data);
signer.BlockUpdate(msg, 0, msg.Length);
return Convert.ToBase64String(signer.GenerateSignature());
}
}
keep getting forbidden. Please help.

If your private key has a password you have to get the pair using another method.
private static string getWalmartSig(string data)
{
try
{
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"key.pem"))
{ // file containing RSA PKCS1 private key
keyPair = DecodePrivateKey(reader.ReadToEnd(), Constants.password); //modified to include password for reading private key.
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
RSAParameters rsaParam = DotNetUtilities.ToRSAParameters((RsaKeyParameters)keyPair.Public);
ISigner signer = SignerUtilities.GetSigner("SHA256WITHRSAENCRYPTION"); //CryptoConfig.MapNameToOID("SHA256") //SHA256WithRSA //modified for using different Encryption.
signer.Init(true, keyPair.Private);
byte[] msg = Encoding.UTF8.GetBytes(data);
signer.BlockUpdate(msg, 0, msg.Length);
return Convert.ToBase64String(signer.GenerateSignature());
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
Refer to Decrypt passphrase protected PEM containing private key for reference.
private static AsymmetricCipherKeyPair DecodePrivateKey(string encryptedPrivateKey, string password) //from https://stackoverflow.com/questions/44767290/decrypt-passphrase-protected-pem-containing-private-key
{
try
{
TextReader textReader = new StringReader(encryptedPrivateKey);
PemReader pemReader = new PemReader(textReader, new PasswordFinder(password));
var privateKeyObject = (AsymmetricCipherKeyPair)pemReader.ReadObject(); //modified for direct casting.
RsaPrivateCrtKeyParameters rsaPrivatekey = (RsaPrivateCrtKeyParameters)privateKeyObject.Private; //modified to use the private key
RsaKeyParameters rsaPublicKey = new RsaKeyParameters(false, rsaPrivatekey.Modulus, rsaPrivatekey.PublicExponent);
AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(rsaPublicKey, rsaPrivatekey);
return kp;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
And now the extension class. Refer to the same link for reference
private class PasswordFinder : IPasswordFinder
{
private string password;
public PasswordFinder(string password)
{
this.password = password;
}
public char[] GetPassword()
{
return password.ToCharArray();
}
}
Notice the changes I have made to the methods. That should get your code running.

Olorunfemi Ajibulu is correct, you have a typo on your AUTH_SIGNATURE header name. This is why you are getting a forbidden. However once you correct that, I can almost guarantee you will be getting a 401 from here on out. API does not seem to be authenticating.

Related

Spring Security SAML2 issue signing SAMLRequest

I'm using spring boot 2.4.1 and spring security SAML2 support
I successfully configured my Service Provider. I created a self-signed certificate and I'm trying to use an IDP that requires signed AuthnRequests.
This is my RelyingPartyRegistrationRepository configuration:
#Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception{
KeyStore ks = KeyStore.getInstance(this.keyStoreType);
char[] pwd = keyStorePassword != null ? keyStorePassword.toCharArray() : null;
String ksName = keyStoreName.replaceAll("classpath:", "");
Resource keystoreRes = new ClassPathResource(ksName);
ks.load(keystoreRes.getInputStream(), pwd);
PrivateKey privateKey = (PrivateKey)ks.getKey(keyStoreAlias, keyStoreKeyPassword.toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(keyStoreAlias);
RelyingPartyRegistration registration = RelyingPartyRegistrations
.fromMetadataLocation(assertingPartyMetadataLocation)
.registrationId(registrationId)
.entityId(spEntityId)
.signingX509Credentials((c) -> c.add(Saml2X509Credential.signing(privateKey, cert)))
.decryptionX509Credentials((c)->c.add(Saml2X509Credential.decryption(privateKey, cert)))
.build();
return new InMemoryRelyingPartyRegistrationRepository(registration);
}
The application successfully starts but,, every time I makes a new request, I got an exception on the IDP side because no KeyInfo element is found in the AuthnRequest
By seeing my application logs, I found this log:
2021-01-06 12:20:35,650 23472 [XNIO-1 task-7] INFO o.o.x.s.support.SignatureSupport - No KeyInfoGenerator was supplied in parameters or resolveable for credential type org.opensaml.security.x509.X509Credential, No KeyInfo will be generated for Signature
I can't understand if I'm missing something in the configuration.
Please note that the same happens also with a certificate released by a trusted CA and not only with self-signed certificate. So I'm thinking it's a kind of configuration mistake I'm doing or a kind of bug.
May you kindly give me tip in how to solve this issue?
Angelo
UPDATE
I solved my current issue. Anyway I think it's a my mistake. Basically I modified the org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory
I added the following method:
private KeyInfoGenerator x509KeyInfoGenerator() {
X509KeyInfoGeneratorFactory generator = new X509KeyInfoGeneratorFactory();
generator.setEmitEntityCertificate(true);
generator.setEmitEntityCertificateChain(true);
return generator.newInstance();
}
I called this method here:
private SignatureSigningParameters resolveSigningParameters(RelyingPartyRegistration relyingPartyRegistration) {
List<Credential> credentials = resolveSigningCredentials(relyingPartyRegistration);
List<String> algorithms = Collections.singletonList(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
List<String> digests = Collections.singletonList(SignatureConstants.ALGO_ID_DIGEST_SHA256);
String canonicalization = SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
SignatureSigningParametersResolver resolver = new SAMLMetadataSignatureSigningParametersResolver();
CriteriaSet criteria = new CriteriaSet();
BasicSignatureSigningConfiguration signingConfiguration = new BasicSignatureSigningConfiguration();
signingConfiguration.setSigningCredentials(credentials);
signingConfiguration.setSignatureAlgorithms(algorithms);
signingConfiguration.setSignatureReferenceDigestMethods(digests);
signingConfiguration.setSignatureCanonicalizationAlgorithm(canonicalization);
criteria.add(new SignatureSigningConfigurationCriterion(signingConfiguration));
try {
SignatureSigningParameters parameters = resolver.resolveSingle(criteria);
parameters.setKeyInfoGenerator(x509KeyInfoGenerator());
Assert.notNull(parameters, "Failed to resolve any signing credential");
return parameters;
}
catch (Exception ex) {
throw new Saml2Exception(ex);
}
}
Now I don't have errors on IdP side but I'm thinking I'm missing something in my configuration. This is my whole web security configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class ApplicazioneMockWebSecurityCfg extends WebSecurityConfigurerAdapter {
static {
OpenSamlInitializationService.requireInitialize((registry) -> {
X509KeyInfoGeneratorFactory generator = new X509KeyInfoGeneratorFactory();
generator.setEmitEntityCertificate(true);
generator.setEmitEntityCertificateChain(true);
NamedKeyInfoGeneratorManager manager = new NamedKeyInfoGeneratorManager();
manager.registerDefaultFactory(generator);
});
}
#Value("${applicazione.mock.external.idp.metadata.location}")
private String assertingPartyMetadataLocation;
#Value("${applicazione.mock.external.idp.metadata.registration.id}")
private String registrationId;
#Value("${server.ssl.key-alias}")
private String keyStoreAlias;
#Value("${server.ssl.key-password}")
private String keyStoreKeyPassword;
#Value("${server.ssl.key-store-password}")
private String keyStorePassword;
#Value("${server.ssl.keystore}")
private String keyStoreName;
#Value("${server.ssl.key-store-type}")
private String keyStoreType;
#Value("${sael.spid.service.provider.applicazione.mock.metadata.entity.id}")
private String spEntityId;
public static final String LOGOUT_URL = "/public/logout";
public static final String LOGIN_PAGE = "/public/home";
#Override
protected void configure(HttpSecurity http) throws Exception {
OpenSamlAuthenticationProvider authenticationProvider = new OpenSamlAuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(responseToken -> {
// Saml2Authentication authentication = OpenSamlAuthenticationProvider
// .createDefaultResponseAuthenticationConverter()
// .convert(responseToken);
Assertion assertion = responseToken.getResponse().getAssertions().get(0);
String username = assertion.getSubject().getNameID().getValue();
List<AttributeStatement> attrStatements = assertion.getAttributeStatements();
String valoreAttributo = null;
Map<String, String> samlAttributes = new HashMap<>();
for (AttributeStatement attrStatement : attrStatements) {
List<Attribute> attrs = attrStatement.getAttributes();
for (Attribute attr : attrs) {
String nomeAttributo = attr.getName();
List<XMLObject> valoriAttributo = attr.getAttributeValues();
//In genere la lista dei valori รจ di 1 elemento
XMLObject valueObj = valoriAttributo.get(0);
valoreAttributo = getValue(valueObj, valoreAttributo);
samlAttributes.put(nomeAttributo, valoreAttributo);
}
}
if( !StringUtils.hasText(valoreAttributo) ) {
throw new IllegalStateException("Impossibile proseguire. Codice Fiscale non trovato tra gli attributi SAML");
}
UserDetails userDetails = new ApplicazioneMockLoggedUser(username, "[PROTECTED]", samlAttributes, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
return new SaelSamlAuthentication(userDetails);
});
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver =
new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrations());
http
.authorizeRequests()
.antMatchers("/protected/**")
.authenticated()
.antMatchers("/public/**")
.permitAll()
.and()
.saml2Login(authorize ->{
authorize
.loginPage(LOGIN_PAGE)
.authenticationManager(new ProviderManager(authenticationProvider))
;
})
.logout(logout->{
logout
.logoutUrl(LOGOUT_URL)
.logoutSuccessHandler(saelLogoutSuccessHanlder())
.logoutRequestMatcher(saelRequestMatcher())
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
//.logoutSuccessUrl(LOGIN_PAGE+"?logout")
.permitAll();
})
.addFilterBefore(new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver()), Saml2WebSsoAuthenticationFilter.class);
}
#Bean
public RequestMatcher saelRequestMatcher() {
return new SaelRequestMatcher();
}
#Bean
public LogoutSuccessHandler saelLogoutSuccessHanlder() {
return new SaelLogoutSuccessHandler();
}
#Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory(
AuthnRequestConverter authnRequestConverter) {
OpenSamlAuthenticationRequestFactory authenticationRequestFactory =
new OpenSamlAuthenticationRequestFactory();
authenticationRequestFactory.setAuthenticationRequestContextConverter(authnRequestConverter);
return authenticationRequestFactory;
}
#Bean
public RelyingPartyRegistrationRepository relyingPartyRegistrations() throws Exception{
KeyStore ks = KeyStore.getInstance(this.keyStoreType);
char[] pwd = keyStorePassword != null ? keyStorePassword.toCharArray() : null;
String ksName = keyStoreName.replaceAll("classpath:", "");
Resource keystoreRes = new ClassPathResource(ksName);
ks.load(keystoreRes.getInputStream(), pwd);
PrivateKey privateKey = (PrivateKey)ks.getKey(keyStoreAlias, keyStoreKeyPassword.toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(keyStoreAlias);
RelyingPartyRegistration registration = RelyingPartyRegistrations
.fromMetadataLocation(assertingPartyMetadataLocation)
.registrationId(registrationId)
.entityId(spEntityId)
.signingX509Credentials((c) -> c.add(Saml2X509Credential.signing(privateKey, cert)))
.decryptionX509Credentials((c)->c.add(Saml2X509Credential.decryption(privateKey, cert)))
.build();
return new InMemoryRelyingPartyRegistrationRepository(registration);
}
private String getValue( XMLObject valueObj, String defaultValue ) {
if( valueObj instanceof XSStringImpl ) {
XSStringImpl stringImpl = (XSStringImpl)valueObj;
return stringImpl.getValue();
}
return defaultValue;
}
}
May you help me in understanding if I'm missing something (I think I'm missing something)

Boolean method not retuning correct value

Ok so I think I'm being a noob because it's a new semester but the method "palindromeTest" always return's false even though the string is equal and the number is a palindrome. (A palindrome example is: (565) 677-6565) (also don't give me the answer outright I want to solve it on my own)
public class IjazZ_PhoneStringPalindrome
{
public static void main(String[] args) throws IOException
{
String phoneNumber;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter a phone number in this format (###) ###-####: ");
phoneNumber = br.readLine();
phoneNumber = justNumbers(phoneNumber);
if (palindromeTest(phoneNumber))
{
System.out.println("This phone number is a palindrome!");
}
else
{
System.out.println("This phone number is not a palindrome!");
}
}
public static String justNumbers(String phoneNumber)
{
StringTokenizer st = new StringTokenizer(phoneNumber, " ()-");
StringBuffer number = new StringBuffer();
while(st.hasMoreTokens())
{
number.append(st.nextToken());
}
phoneNumber = number.toString();
return phoneNumber;
}
public static boolean palindromeTest(String pNumber)
{
StringBuffer reversedNumber = new StringBuffer(pNumber);
reversedNumber.reverse().toString();
if(pNumber.equals(reversedNumber))
{
return true;
}
else
{
return false;
}
}
}
You don't assign the value returned by reversedNumber.reverse().toString()to reversedNumber.
Do
String reversedNumberString = reversedNumber.reverse().toString();
And by the way, you can just return
return pNumber.equals(reversedNumber); - the if/else statement is unnecessary.

AWS Cognito user authentication Missing required parameter SRP_A

I am trying to use AWS Cognito services for user authentication through ruby SDK.
I could able to sign_up, confirm sign_up process using the methods
resp = client.sign_up({ client_id: "ClientIdType",
secret_hash: "SecretHashType",
username: "UsernameType",
password: "PasswordType",
user_attributes: [{ name:"AttributeNameType",
value: "AttributeValueType",
}],
validation_data: [{
name: "AttributeNameType",
value: "AttributeValueType",
}]
})
and confirm_sign_up using
resp = client.confirm_sign_up({client_id: "ClientIdType",
secret_hash: "SecretHashType",
username: "UsernameType",
confirmation_code: "ConfirmationCodeType"
})
But while trying to sign in the user through initiate_auth I am getting an error Missing required parameter SRP_A
cog_provider.initiate_auth({client_id: "xxxxxxxxx", auth_parameters: { username: "xxx", password: "xxx"}, auth_flow: "USER_SRP_AUTH"})
What does SRP_A indicate where to find it.
I have searched for this problem and It is suggested to use the admin_initiate_auth method for signing in a user which I don't believe a best practice.
Yes, SRP_A is a large integer as defined by the Secure Remote Password Protocol. Are you trying to do SRP or just authenticate with username and password. For username/password authentication you should use the AdminInitiateAuth operation.
In our SDKs, you can see the parameters that need to be computed and passed. Take for example the Javascript SDK:
https://github.com/aws/amazon-cognito-identity-js/blob/master/src/CognitoUser.js#L152
Or in the Android SDK:
https://github.com/aws/aws-sdk-android/blob/master/aws-android-sdk-cognitoidentityprovider/src/main/java/com/amazonaws/mobileconnectors/cognitoidentityprovider/CognitoUser.java#L2123
For AWS Java SDK:
here is the class to manage this:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.math.pro.ak.util.cognito;
import com.amazonaws.AmazonClientException;
import com.amazonaws.util.StringUtils;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
*
* #author marcus
*/
public class AuthenticationHelper {
private BigInteger a;
private BigInteger A;
private String poolName;
public AuthenticationHelper(String userPoolName) {
do {
a = new BigInteger(EPHEMERAL_KEY_LENGTH, SECURE_RANDOM).mod(N);
A = GG.modPow(a, N);
} while (A.mod(N).equals(BigInteger.ZERO));
if (userPoolName.contains("_")) {
poolName = userPoolName.split("_", 2)[1];
} else {
poolName = userPoolName;
}
}
public BigInteger geta() {
return a;
}
public BigInteger getA() {
return A;
}
private static final String HEX_N = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
private static final BigInteger N = new BigInteger(HEX_N, 16);
private static final BigInteger GG = BigInteger.valueOf(2);
private static final BigInteger KK;
private static final int EPHEMERAL_KEY_LENGTH = 1024;
private static final int DERIVED_KEY_SIZE = 16;
private static final String DERIVED_KEY_INFO = "Caldera Derived Key";
private static final ThreadLocal<MessageDigest> THREAD_MESSAGE_DIGEST = new ThreadLocal<MessageDigest>() {
#Override
protected MessageDigest initialValue() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (final NoSuchAlgorithmException e) {
throw new AmazonClientException("Exception in authentication", e);
}
}
};
private static final SecureRandom SECURE_RANDOM;
static {
try {
SECURE_RANDOM = SecureRandom.getInstance("SHA1PRNG");
final MessageDigest messageDigest = THREAD_MESSAGE_DIGEST.get();
messageDigest.reset();
messageDigest.update(N.toByteArray());
final byte[] digest = messageDigest.digest(GG.toByteArray());
KK = new BigInteger(1, digest);
} catch (final NoSuchAlgorithmException e) {
throw new AmazonClientException(e.getMessage(), e);
}
}
public byte[] getPasswordAuthenticationKey(String userId,
String userPassword,
BigInteger B,
BigInteger salt) {
// Authenticate the password
// u = H(A, B)
final MessageDigest messageDigest = THREAD_MESSAGE_DIGEST.get();
messageDigest.reset();
messageDigest.update(A.toByteArray());
final BigInteger u = new BigInteger(1, messageDigest.digest(B.toByteArray()));
if (u.equals(BigInteger.ZERO)) {
throw new AmazonClientException("Hash of A and B cannot be zero");
}
// x = H(salt | H(poolName | userId | ":" | password))
messageDigest.reset();
messageDigest.update(poolName.getBytes(StringUtils.UTF8));
messageDigest.update(userId.getBytes(StringUtils.UTF8));
messageDigest.update(":".getBytes(StringUtils.UTF8));
final byte[] userIdHash = messageDigest.digest(userPassword.getBytes(StringUtils.UTF8));
messageDigest.reset();
messageDigest.update(salt.toByteArray());
final BigInteger x = new BigInteger(1, messageDigest.digest(userIdHash));
final BigInteger s = (B.subtract(KK.multiply(GG.modPow(x, N)))
.modPow(a.add(u.multiply(x)), N)).mod(N);
Hkdf hkdf = null;
try {
hkdf = Hkdf.getInstance("HmacSHA256");
} catch (final NoSuchAlgorithmException e) {
throw new AmazonClientException(e.getMessage(), e);
}
hkdf.init(s.toByteArray(), u.toByteArray());
final byte[] key = hkdf.deriveKey(DERIVED_KEY_INFO, DERIVED_KEY_SIZE);
return key;
}
}
And call this the method:
userAuth.put("SRP_A", new AuthenticationHelper(request.getUsername()).getA().toString(16));

Custom extension element in Stanza for Smack 4.1.4

I am moving my android application from asmack-android library to Smack 4.1.4. I have some PacketExtensions in the asmack version of Smack, which uses PacketExtension and PacketExtensionProvider classes to handle. Since the PacketExtension is deprecated in Smack 4.1.4, I am confused among the classes and interfaces ExtensionElement, DataPacketExtension, ExtensionElementProvider , DefaultExtensionElement. Could any one of you give me an example of creating an extension which can be added with stanza and parse back...https://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware /smack/packet/DefaultExtensionElement.htmlhttps://www.igniterealtime.org/builds/smack/docs/latest/javadoc/org/jivesoftware /smack/provider/ExtensionElementProvider.html
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
Log.e("message --->", message.toXML().toString());
This will produce the following stanza
<message id='923442621149' type='chat'><body>shanraisshan</body></message>
1. CUSTOM EXTENSION STANZA TYPE-1
In order to generate below custom extension stanza
<message id='923442621149' type='chat'><body>shanraisshan</body>
<reply xmlns='shayan:reply' rText='this is custom attribute'/>
</message>
where reply is a custom extension, which contains
Element (reply)
Namespace (shayan:reply)
the list of default xmpp namespaces are available at Official XMPP website
Do following steps
1. Add ReplyExtension.java in your project
ReplyExtension.java
package com.xmpp.extensions;
import org.jivesoftware.smack.packet.DefaultExtensionElement;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.provider.EmbeddedExtensionProvider;
import org.jivesoftware.smack.util.XmlStringBuilder;
import java.util.List;
import java.util.Map;
/**
* Shayan Rais (http://shanraisshan.com)
* created on 9/7/2016
*/
public class ReplyExtension implements ExtensionElement {
public static final String NAMESPACE = "shayan:reply";
public static final String ELEMENT = "reply";
String rText = null;
static final String ATTRIBUTE_REPLY_TEXT = "rText";
#Override
public String getElementName() {
return ELEMENT;
}
#Override
public String getNamespace() {
return NAMESPACE;
}
#Override
public XmlStringBuilder toXML() {
XmlStringBuilder xml = new XmlStringBuilder(this);
xml.attribute(ATTRIBUTE_REPLY_TEXT, getReplyText());
xml.closeEmptyElement();
return xml;
}
//__________________________________________________________________________________________________
public void setReplyText(String _rText) {
rText = _rText;
}
public String getReplyText() {
return rText;
}
//__________________________________________________________________________________________________
public static class Provider extends EmbeddedExtensionProvider<ReplyExtension> {
#Override
protected ReplyExtension createReturnExtension(String currentElement, String currentNamespace, Map<String, String> attributeMap, List<? extends ExtensionElement> content) {
ReplyExtension repExt = new ReplyExtension();
repExt.setReplyText(attributeMap.get(ATTRIBUTE_REPLY_TEXT));
return repExt;
}
}
}
2. Register ReplyExtension in your Provider Manager
ProviderManager.addExtensionProvider(ReplyExtension.ELEMENT, ReplyExtension.NAMESPACE, new ReplyExtension.Provider());
FOR SENDING MESSAGES
You can generate the custom extension stanza TYPE-1 by using following code
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
//adding custom reply extension
ReplyExtension repExt = new ReplyExtension();
repExt.setReplyText("this is custom attribute");
message.addExtension(repExt);
Log.e("message --->", message.toXML().toString());
DURING RECEIVING MESSAGES
Now during receiving custom extension stanzas, you need to cast the extension to get attribute values.
//check for message with reply extension
ExtensionElement packetExtension = message.getExtension(ReplyExtension.NAMESPACE);
ReplyExtension repExt = (ReplyExtension)packetExtension;
if(repExt!=null) {
Log.e("--->", " --- LOG REPLY EXTENSION ---");
Log.e("--->", repExt.toXML() + "");
Log.e("--->", repExt.getReplyText() + ""); //this is custom attribute
}
_______________________________________________________
2. CUSTOM EXTENSION STANZA TYPE-2
In order to generate below custom extension stanza
<message id='923442621149' type='chat'><body>shanraisshan</body>
<reply xmlns='shayan:reply'><rText>this is custom attribute</rText></reply>
</message>
FOR SENDING MESSAGES
You can generate the custom extension stanza TYPE-2 by using following code
Message message = new Message();
message.setStanzaId("923442621149");
message.setType(Type.chat);
message.setBody("shanraisshan");
//adding custom reply extension
DefaultExtensionElement repExt = new DefaultExtensionElement("reply", "shayan:reply");
repExt.setValue("rText", "this is custom attribute");
message.addExtension(repExt);
Log.e("message --->", message.toXML().toString());
DURING RECEIVING MESSAGES
DefaultExtensionElement repExt = (DefaultExtensionElement) message.getExtension("shayan:reply");
if(repExt!=null) {
Log.e("--->", " --- LOG REPLY EXTENSION ---");
Log.e(getClass().getSimpleName(), repExt.getValue("rText"));
}
Finally figured it out.... Here is the solution for it...
import org.jivesoftware.smack.packet.DefaultExtensionElement;
public class IM_FileSharing_Extension extends DefaultExtensionElement implements
IM_Commons_Extension_FileSharing {
private String fileUrl;
private String fileType;
private String base64preview;
private String fileId;
private String fileSize;
public IM_FileSharing_Extension(String fileUrl, String fileType,
String base64preview, String fileId, String fileSize) {
super(FILE_TAG, XMLNS);
this.fileUrl = fileUrl;
this.fileType = fileType;
this.base64preview = base64preview;
this.fileId = fileId;
this.fileSize = fileSize;
}
#Override
public String toXML() {
StringBuilder sb = new StringBuilder("<" + FILE_TAG + " xmlns=\""
+ XMLNS + "\" ");
sb.append(FILE_URL + "=\"" + fileUrl + "\" ");
sb.append(FILE_ID + "=\"" + fileId + "\" ");
sb.append(FILE_TYPE + "=\"" + fileType + "\" ");
sb.append(FILE_SIZE + "=\"" + fileSize + "\">");
sb.append("<" + FILE_PREVIEW_TAG + ">" + base64preview + "</"
+ FILE_PREVIEW_TAG + ">");
sb.append("</" + FILE_TAG + ">");
return sb.toString();
}
public String getFileUrl() {
return fileUrl;
}
public void setFileUrl(String fileUrl) {
this.fileUrl = fileUrl;
}
public String getBase64preview() {
return base64preview;
}
public void setBase64preview(String base64preview) {
this.base64preview = base64preview;
}
public String getFileId() {
return fileId;
}
public void setFileId(String fileId) {
this.fileId = fileId;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public String getFileSize() {
return fileSize;
}
public void setFileSize(String fileSize) {
this.fileSize = fileSize;
}
}
Provider for the above extension is as follows...
import java.io.IOException;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.provider.ExtensionElementProvider;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.Log;
public class IM_FileSharingExtension_Provider extends
ExtensionElementProvider<IM_FileSharing_Extension> implements
IM_Commons_Extension_FileSharing {
static final String TAG = "file_extension";
#Override
public IM_FileSharing_Extension parse(XmlPullParser parser, int initialDepth)
throws XmlPullParserException, IOException, SmackException {
IM_FileSharing_Extension fileExtension = null;
boolean stop = false;
String n = null;
int evtType;
String fileUrl = null;
String fileType = null;
String fileId = null;
String fileSize = null;
while (!stop) {
evtType = parser.getEventType();
n = parser.getName();
Log.d(TAG, "n:" + n + " evt:" + evtType);
switch (evtType) {
case XmlPullParser.START_TAG:
if (FILE_TAG.equals(n)) {
fileUrl = parser.getAttributeValue("", FILE_URL);
fileType = parser.getAttributeValue("", FILE_TYPE);
fileId = parser.getAttributeValue("", FILE_ID);
fileSize = parser.getAttributeValue("", FILE_SIZE);
evtType = parser.next();
}
if (FILE_PREVIEW_TAG.equals(parser.getName())) {
String basePreview = parser.nextText();
fileExtension = new IM_FileSharing_Extension(fileUrl,
fileType, basePreview, fileId, fileSize);
}
evtType = parser.next();
break;
case XmlPullParser.END_TAG:
if (parser.getName().equals(FILE_TAG)) {
return fileExtension;
}
evtType = parser.next();
}
}
return null;
}
}
And should be added in Provider manager as following....
ProviderManager.addExtensionProvider(
IM_Commons_Extension_FileSharing.FILE_TAG,
IM_Commons_Extension_FileSharing.XMLNS,
new IM_FileSharingExtension_Provider());

MD5 Heaping Using IOS Exactly Like Java

This is my Code in java.Here I am converting a string to byte array and heaping it using MD algorithm with the Help of digest in java.
public static byte[] passwordToKey (String password) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance ("MD5");
} catch (NoSuchAlgorithmException ex) {
return new byte[0];
}
byte[] passwordBytes = null;
try {
passwordBytes = password.getBytes ("ISO-8859-1");
} catch (UnsupportedEncodingException ex) {
passwordBytes = new byte[0];
}
return md.digest(passwordBytes);
}
The problem is the value after encryption in java and ios are different.Can someone give me the exact code in ios for the above?

Resources