1

I'm trying to get my integrations updated to handle this forced use of token authentication for NetSuite web services. However, I'm stuck getting the following:

[System.Web.Services.Protocols.SoapException] Ambiguous authentication

I've tried various things with no improvement. Doesn't seem to matter if I use a token created beforehand, or have one generated. I'm not creating a "Cookie Container", or adding a standard Passport object. I've tried a few different methods for generating a signature and a nonce value. I've even switched between SHA1 and SHA256 thinking that might make a difference. I'm going to include my code here. Hopefully someone can see what I'm doing wrong.

FYI, there are some components in here from trying what I found in this post: Ambiguous Authentication in Netsuite Token Based API call

static void Main(string[] args) {
    NameValueCollection _dataCollection = ConfigurationManager.AppSettings;
    NSCreds crd = new NSCreds(_dataCollection); /// just building a data object to handle credentials and keys
    NSWS ns = new NSWS(crd, _dataCollection["appId"]); // token passport gets built here

    // now to make a call to just get a single file from the File Cabinet

    RecordRef pullFile = new RecordRef();
    pullFile.type = RecordType.file;
    pullFile.typeSpecified = true;
    pullFile.internalId = _dataCollection["fileId"];
    ReadResponse rres = ns.service.get(pullFile); // this line throws the error highlighted above
}

public NSWS(NSCreds c, String appId) {
    CheckConnectionSecurity(); // makes sure connection security is set to TLS 1.2
    _pageSize = 100;
    service = new NetSuiteService();
    service.Timeout = 1000 * 60 * 60 * 2;
    service.tokenPassport = prepareTokenPassport(c);
    ApplicationInfo appInfo = new ApplicationInfo();
    appInfo.applicationId = appId;
    service.applicationInfo = appInfo;
}

public TokenPassport prepareTokenPassport(NSCreds c) {
    long TimeStamp = ComputeTimestamp();
    String nonce = CreateNonce_1();
    NSToken token = null;
    if (String.IsNullOrEmpty(c.tokenId) && String.IsNullOrEmpty(c.tokenSecret)) {
        token = GetToken(c.customerKey, c); // make calls to NetSuite to generate token data and build custom object
    } else {
        token = new NSToken(c.tokenId,c.tokenSecret); // build custom object from apps settings data
    }
    String signature = ComputeSignature(c.account, c.customerKey, c.customerSecret, token.tokenId, token.tokenSecret, nonce, TimeStamp);

    TokenPassport tokenPassport = new TokenPassport();
    tokenPassport.account = c.account;
    tokenPassport.consumerKey = c.customerKey;
    tokenPassport.token = token.tokenId;
    tokenPassport.nonce = nonce;
    tokenPassport.timestamp = TimeStamp;
    TokenPassportSignature signatureElement = new TokenPassportSignature();
    signatureElement.algorithm = "HMAC-SHA1"; // "HMAC-SHA256";
    signatureElement.Value = signature;
    tokenPassport.signature = signatureElement;

    return tokenPassport;
}

private static long ComputeTimestamp() {
    return ((long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
}

private String CreateNonce_1() {
    int length = 20;
    String AllowedChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    StringBuilder nonce = new StringBuilder();
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] rnd = new byte[1];

    for (int i = 0; i < length; i++) {
        while (true) {
            rng.GetBytes(rnd);
            char c = (char)rnd[0];
            if (AllowedChars.IndexOf(c) != (-1)) {
                nonce.Append(rnd[0]);
                break;
            }
        }
    }

    return nonce.ToString();
}

private static string CreateNonce_2() {
    return Guid.NewGuid().ToString("N");
}

private String CreateNonce_3() {
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] data = new byte[20];
    rng.GetBytes(data);
    int value = Math.Abs(BitConverter.ToInt32(data, 0));
    return value.ToString();
}

private string ComputeSignature(String account, String cKey, String cSecret, String token, String tokenSecret, String nonce, long timeStamp) {
    String baseString = String.Format("{0}&{1}&{2}&{3}&{4}",account,cKey,token,nonce,timeStamp);
    String key = String.Format("{0}&{1}", cSecret, tokenSecret);

    // previous method for encoding the signature
    // Mac is a custom object found from another post here
    // EncryptionMethods is an enumeration from that same post
    /*
    //using (var secretKey = new SecretKeySpec(GetBytes(key), EncryptionMethods.HMACSHA256))
    using (var secretKey = new SecretKeySpec(GetBytes(key), EncryptionMethods.HMACSHA1))
    using (Mac mac = new Mac(secretKey, baseString)) {
        return mac.AsBase64();
    }
    */

    //HMACSHA256 hashObject = new HMACSHA256(Encoding.UTF8.GetBytes(key));
    HMACSHA1 hashObject = new HMACSHA1(Encoding.UTF8.GetBytes(key));
    byte[] signature = hashObject.ComputeHash(Encoding.UTF8.GetBytes(baseString));
    string encodedSignature = Convert.ToBase64String(signature);

    return encodedSignature;
}
Michael McCauley
  • 853
  • 1
  • 12
  • 37

2 Answers2

2

It turns out that the problem was setting the Application ID while also specifying a Token Passport. Doing so actually creates a conflict with the system not knowing which to use for authentication, since the token itself references the Application ID internally. So, removed the bit where the Application ID was being set to the service object and everything started working correctly.

Michael McCauley
  • 853
  • 1
  • 12
  • 37
  • This really helped me. I removed the entire ... section from the Header leaving only the tokenPassport and it worked – Rizan Zaky Apr 24 '21 at 06:13
-2

Try to use this code for token based authentication

TokenPassport tokenPassport = new TokenPassport();
tokenPassport.account = account; //Account ID
tokenPassport.consumerKey = consumerKey; //Consumer Key
tokenPassport.token = tokenId; // Token ID
tokenPassport.nonce = nonce;   //It is some calculated value with the help of RNGCryptoServiceProvider class.
tokenPassport.timestamp = timestamp;
tokenPassport.signature = signature; // It is TokenPassportSignature  

TokenPassportSignature also uses Account ID, Token ID & Token Secret. It has some algorithms.

Sumit Jha
  • 27
  • 4