How do i know, which Peer did the Transaction in Hyperledger Fabric Go? - go

I am working on getting a transaction id info, which will give the peer details for the transaction. Currently, I am able to retrieve the History for a key, which gives me the list of transaction committed to that key.
MyCode:
historyRes, err := stub.GetHistoryForKey(userNameIndexKey)
if err != nil {
return shim.Error(fmt.Sprintf("Unable to get History key from the ledger: %v", err))
}
for historyRes.HasNext() {
history, errIt := historyRes.Next()
if errIt != nil {
return shim.Error(fmt.Sprintf("Unable to retrieve history in the ledger: %v", errIt))
}
deleted := history.GetIsDelete()
ds := strconv.FormatBool(deleted)
fmt.Println("History TxId = "+history.GetTxId()+" -- Delete = "+ds)
}
Output
History TxId = 78c8d17c668d7a9df8373fd85df4fc398388976a1c642753bbf73abc5c648dd8 -- Deleted = false
History TxId = 102bbb64a7ca93367334a8c98f1f7be17e6a8d5277f0167c73da47072d302fa3 -- Deleted = true
But I don't know, which peer did this transaction. Is there any API available in fabric-sdk-go to retrieve peer info for a transaction id.
please suggest me some solution.

The call stub.GetHistoryForKey(userNameIndexKey) will query the state database and not the ledger (channel). The information about the identity who made the transaction is stored in the block.
I have implemented the same thing with NodeJS SDK. However, Go SDK too contains similar API calls. The following steps worked for me:
Using your SDK, get the transactionId
Use the SDK function for querying block by transactionId. References here.
At this step, you'll get the block. Now the identity of the submitter is located within this block. Hints: Payload -> Header -> Signature Header -> Creater -> IdBytes.
These identity bytes are the X509 certs of the submitter. You can read the certificate info to find out which member did submit this transaction. The subject and OUs will indicate the Organization of the peer that did the transaction.

Related

Dynamics 365 Customer Service : Email sent from one queue to another queue is getting linked to same ticket

I am facing an issue in Dynamics 365.
Let's say I have 2 queues - Queue1 & Queue2 and have enabled case creation rule on both the queues. Initially, the customer sent an email to Queue1 and converted it into the case, and I want to forward this email to Queue2.
When I forward email FROM Queue1 TO Queue2, it comes back as 'incoming' email to Dynamics through Queue2, but again gets linked to the same old case present in Queue1. I want that, it should create a new case in Queue2.
I tried a pre-create plugin also to clear regardingobject in an incoming email if the sender is a Dynamics queue and as per traces, code is clearing regardingobectid as well. However, it still gets linked to the same ticket somehow.
Is there anyone who faced the same issue and got a workaround.
Plugin code snippet - registered on Email Pre-create sync.
TargetEntity = (Entity)PluginContext.InputParameters["Target"];
var sender = TargetEntity["sender"].ToString().ToLowerInvariant();
EntityCollection senderQueue = GetQueue(sender);
if (senderQueue?.Entities != null && senderQueue.Entities.Count != 0)
{
TracingService.Trace("sender is a queue");
TracingService.Trace("updating : TargetEntity['regardingobjectid'] = null to platform");
TargetEntity["regardingobjectid"] = null;
}```
I was finally able to do it after clearing 3 attributes in the incoming email's target entity.
I have written a pre-validate sync plugin on email cleared below 3 fields :-
TargetEntity["regardingobjectid"] = null;
// this line -- parentactivityid fixed the issue.
TargetEntity["parentactivityid"] = null;
TargetEntity["trackingtoken"] = null;

golang get only one stat from json

i tried to get one stat from web api request in json.
This is what called https://api.coinmarketcap.com/v1/ticker/ethereum/
I use this github code example // Get info about coin
coinInfo, err := coinApi.GetCoinData("ethereum")
if err != nil {
log.Println(err)
} else {
fmt.Println(coinInfo)
}
My result in log says
{ethereum Ethereum ETH 2 830.48 0.100287 3.23573e+09 8.0977392218e+10 9.7506734e+07 9.7506734e+07 0.61 -0.65 -7.36 1518176353}
But i want only the price_usd if you look at the api domain. Why cannot get only price?
Already tried coinInfo['price_usd'] but its all not working
Here you find the functions to run the GetCoinData
https://github.com/miguelmota/go-coinmarketcap/blob/master/coinmarketcap.go
Can someone help me to get only the price_usd from api in golang?
According to the docs, you can use the PriceUsd field of the Coin type for this.

gRPC context on the client side

I am building a client/server system in go, using gRPC and protobuf (and with a gRPC gateway to REST).
I use metadata in the context on the server side to carry authentication data from the client, and that works perfectly well.
Now, I'd like the server to set some metadata keys/values so that the client can get them, alongside with the response. How can I do that? Using SetHeader and SendHeader? Ideally, I'd like every single response from the server to integrate that metadata (can be seen as some kind of UnaryInterceptor, but on the response rather than the request?)
Here is the code for the server and for the client.
I finally found my way: https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md
So basically, grpc.SetHeader() + grpc.SendHeader() and grpc.SetTrailer() are totally what I was looking for. On the client side, grpc.Header() and grpc.Trailer() functions need to be passed to the RPC call, and their argument is a metadata.MD object to be filled.
On the client side, define your receiving metadata:
var header, trailer metadata.MD
Then, pass it to the SomeRPCCall() unary RPC:
response, err := client.SomeRPCCall(
context.Background(),
proto.MyMessage{},
grpc.Header(&header),
grpc.Trailer(&trailer),
)
And now, you can check what's in your metadata:
for key, value := range header {
fmt.Printf("%s => %s", key, value)
}
for key, value := range trailer {
fmt.Printf("%s => %s", key, value)
}
On the server side, you can:
force the data to be sent right after the RPC is received (but before it's processed):
grpc.SendHeader(ctx, metadata.New(map[string]string{"my-key": "my-value"}))
or set & send the metadata at the end of the RPC process (along with the Status):
grpc.SetTrailer(ctx, metadata.New(map[string]string{"my-key": "my-value"}))

duplicate key given in txn request while trying to remove all keys by prefix and put them again

Trying to use coreos/jetcd for updating haproxy settings in etcd from Java-code.
What I want to achieve is:
remove all endpoints for single host
add an updated data for given host
I want to remove all keys by prefix and put actual data in etcd as atomic operation.
That's why I tried to use etcd transactions. My code is:
Op.DeleteOp deleteOp = Op.delete(
fromString(prefix),
DeleteOption.newBuilder().withPrefix(fromString(prefix)).build()
);
Txn tx = kvClient.txn().Else(deleteOp);
newKvs.forEach((k,v) -> {
tx.Else(Op.put(fromString(k), fromString(v), DEFAULT));
});
try {
tx.commit().get();
} catch (InterruptedException | ExecutionException e) {
log.error("ETCD transaction failed", e);
throw new RuntimeException(e);
}
ETCD v3 API is used (etcd v3.2.9). KVstore is initially empty and I want to add 3 records.
prefix value is:
/proxy-service/hosts/example.com
and kvs is a Map:
"/proxy-service/hosts/example.com/FTP/0" -> "localhost:10021"
"/proxy-service/hosts/example.com/HTTPS/0" -> "localhost:10443"
"/proxy-service/hosts/example.com/HTTP/0" -> "localhost:10080"
An Exception happens on commit().get() line with the following root cause:
Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: etcdserver: duplicate key given in txn request
at io.grpc.Status.asRuntimeException(Status.java:526)
at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:427)
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:41)
at com.coreos.jetcd.internal.impl.ClientConnectionManager$AuthTokenInterceptor$1$1.onClose(ClientConnectionManager.java:267)
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:419)
at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:60)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:493)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$500(ClientCallImpl.java:422)
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:525)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:102)
... 3 more
What am i doing wrong and how else can I complete several etcd changes as atomic operation?
It looks like that the operations to remove a key and then adding a new value for the same key cannot be in the same txn. According to the The etcd APIv3 documentation:
Txn processes multiple requests in a single transaction. A txn request increments the revision of the key-value store and generates events with the same revision for every completed request. It is not allowed to modify the same key several times within one txn.

Win32: How to validate credentials against Active Directory?

It has been asked, and answered for .NET, but now it's time to get an answer for native Win32 code:
How do i validate a Windows username and password?
i asked this question before for managed code. Now it's time for the native solution.
It needs to be pointed the pitfalls with some of the more commonly proposed solutions:
Invalid Method 1. Query Active Directory with Impersonation
A lot of people suggest querying the Active Directory for something. If an exception is thrown, then you know the credentials are not valid - as is suggested in this stackoverflow question.
There are some serious drawbacks to this approach however:
You are not only authenticating a domain account, but you are also doing an implicit authorization check. That is, you are reading properties from the AD using an impersonation token. What if the otherwise valid account has no rights to read from the AD? By default all users have read access, but domain policies can be set to disable access permissions for restricted accounts (and or groups).
Binding against the AD has a serious overhead, the AD schema cache has to be loaded at the client (ADSI cache in the ADSI provider used by DirectoryServices). This is both network, and AD server, resource consuming - and is too expensive for a simple operation like authenticating a user account.
You're relying on an exception failure for a non-exceptional case, and assuming that means invalid username and password. Other problems (e.g. network failure, AD connectivity failure, memory allocation error, etc) are then mis-intrepreted as authentication failure.
The use of the DirectoryEntry class is .NET is an example of an incorrect way to verify credentials:
Invalid Method 1a - .NET
DirectoryEntry entry = new DirectoryEntry("persuis", "iboyd", "Tr0ub4dor&3");
object nativeObject = entry.NativeObject;
Invalid Method 1b - .NET #2
public static Boolean CheckADUserCredentials(String accountName, String password, String domain)
{
Boolean result;
using (DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, accountName, password))
{
using (DirectorySearcher searcher = new DirectorySearcher(entry))
{
String filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
searcher.Filter = filter;
try
{
SearchResult adsSearchResult = searcher.FindOne();
result = true;
}
catch (DirectoryServicesCOMException ex)
{
const int SEC_E_LOGON_DENIED = -2146893044; //0x8009030C;
if (ex.ExtendedError == SEC_E_LOGON_DENIED)
{
// Failed to authenticate.
result = false;
}
else
{
throw;
}
}
}
}
As well as querying Active Directory through an ADO connection:
Invalid Method 1c - Native Query
connectionString = "Provider=ADsDSOObject;
User ID=iboyd;Password=Tr0ub4dor&3;
Encrypt Password=True;Mode=Read;
Bind Flags=0;ADSI Flag=-2147483648';"
SELECT userAccountControl
FROM 'LDAP://persuis/DC=stackoverflow,DC=com'
WHERE objectClass='user' and sAMAccountName = 'iboyd'
These both fail even when your credentials are valid, but you do not have permission to view your directory entry:
Invalid Method 2. LogonUser Win32 API
Others have suggested using the LogonUser() API function. This sounds nice, but unfortunatly the calling user sometimes needs a permission ususally only given to the operating system itself:
The process calling LogonUser requires
the SE_TCB_NAME privilege. If the
calling process does not have this
privilege, LogonUser fails and
GetLastError returns
ERROR_PRIVILEGE_NOT_HELD.
In some
cases, the process that calls
LogonUser must also have the
SE_CHANGE_NOTIFY_NAME privilege
enabled; otherwise, LogonUser fails
and GetLastError returns
ERROR_ACCESS_DENIED. This privilege is
not required for the local system
account or accounts that are members
of the administrators group. By
default, SE_CHANGE_NOTIFY_NAME is
enabled for all users, but some
administrators may disable it for
everyone.
Handing out the "Act as a part of the operating system" privelage is not something you want to do willy-nilly - as Microsoft points out in a knowledge base article:
...the process that is calling
LogonUser must have the SE_TCB_NAME
privilege (in User Manager, this is
the "Act as part of the Operating
System" right). The SE_TCB_NAME
privilege is very powerful and
should not be granted to any arbitrary user just so that they can
run an application that needs to
validate credentials.
Additionally, a call to LogonUser() will fail if a blank password is specified.
Valid .NET 3.5 Method - PrincipalContext
There is a validation method, only available in .NET 3.5 and newer, that allows authentication by a user without performing an authorization check:
// create a "principal context" - e.g. your domain (could be machine, too)
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "stackoverflow.com"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("iboyd", "Tr0ub4dor&3")
}
Unfortunately this code is only available in .NET 3.5 and later.
It's time to find the native equivalent.
Here is Microsoft's recommendation.
As for the other answers, I'm not really sure why you're shooting them down. You are complaining about (relatively edge case) failures while trying to validate credentials, but if you are going to actually do something with those credentials then that operation is just going to fail anyway. If you are not going to actually do something with those credentials, then why do you need to validate them in the first place? It seems like a somewhat contrived situation, but obviously I don't know what you're trying to accomplish.
For the native equivalnt of your valid .NET solution see this MSDN page and ldap_bind
Howerver I think that LogonUser is the right API for the task when use with LOGON32_LOGON_NETWORK. Note that the limitation of SE_CHANGE_NOTIFY_NAME is only for Windows 2000 (so Windows XP and newer do not require this priviledge) and that by default SE_CHANGE_NOTIFY_NAME is enabled for all users. Also the MSDN page says
The SE_TCB_NAME privilege is not required for this function unless you are logging onto a Passport account.
In this case you are logging onto an AD account so SE_TCB_NAME is not required.
I might as well post the native code to validate a set of Windows credentials. It took a while to implement.
function TSSPLogon.LogonUser(username, password, domain: string; packageName: string='Negotiate'): HRESULT;
var
ss: SECURITY_STATUS;
packageInfo: PSecPkgInfoA;
cbMaxToken: DWORD;
clientBuf: PByte;
serverBuf: PByte;
authIdentity: SEC_WINNT_AUTH_IDENTITY;
cbOut, cbIn: DWORD;
asClient: AUTH_SEQ;
asServer: AUTH_SEQ;
Done: boolean;
begin
{
If domain is blank will use the current domain.
To force validation against the local database use domain "."
sspiProviderName is the same of the Security Support Provider Package to use. Some possible choices are:
- Negotiate (Preferred)
Introduced in Windows 2000 (secur32.dll)
Selects Kerberos and if not available, NTLM protocol.
Negotiate SSP provides single sign-on capability called as Integrated Windows Authentication.
On Windows 7 and later, NEGOExts is introduced which negotiates the use of installed
custom SSPs which are supported on the client and server for authentication.
- Kerberos
Introduced in Windows 2000 and updated in Windows Vista to support AES) (secur32.dll)
Preferred for mutual client-server domain authentication in Windows 2000 and later.
- NTLM
Introduced in Windows NT 3.51 (Msv1_0.dll)
Provides NTLM challenge/response authentication for client-server domains prior to
Windows 2000 and for non-domain authentication (SMB/CIFS)
- Digest
Introduced in Windows XP (wdigest.dll)
Provides challenge/response based HTTP and SASL authentication between Windows and non-Windows systems where Kerberos is not available
- CredSSP
Introduced in Windows Vista and available on Windows XP SP3 (credssp.dll)
Provides SSO and Network Level Authentication for Remote Desktop Services
- Schannel
Introduced in Windows 2000 and updated in Windows Vista to support stronger AES encryption and ECC (schannel.dll)
Microsoft's implementation of TLS/SSL
Public key cryptography SSP that provides encryption and secure communication for
authenticating clients and servers over the internet. Updated in Windows 7 to support TLS 1.2.
If returns false, you can call GetLastError to get the reason for the failure
}
// Get the maximum authentication token size for this package
ss := sspi.QuerySecurityPackageInfoA(PAnsiChar(packageName), packageInfo);
if ss <> SEC_E_OK then
begin
RaiseWin32Error('QuerySecurityPackageInfo "'+PackageName+'" failed', ss);
Result := ss;
Exit;
end;
try
cbMaxToken := packageInfo.cbMaxToken;
finally
FreeContextBuffer(packageInfo);
end;
// Initialize authorization identity structure
ZeroMemory(#authIdentity, SizeOf(authIdentity));
if Length(domain) > 0 then
begin
authIdentity.Domain := PChar(Domain);
authIdentity.DomainLength := Length(domain);
end;
if Length(userName) > 0 then
begin
authIdentity.User := PChar(UserName);
authIdentity.UserLength := Length(UserName);
end;
if Length(Password) > 0 then
begin
authIdentity.Password := PChar(Password);
authIdentity.PasswordLength := Length(Password);
end;
AuthIdentity.Flags := SEC_WINNT_AUTH_IDENTITY_ANSI; //SEC_WINNT_AUTH_IDENTITY_UNICODE
ZeroMemory(#asClient, SizeOf(asClient));
ZeroMemory(#asServer, SizeOf(asServer));
//Allocate buffers for client and server messages
GetMem(clientBuf, cbMaxToken);
GetMem(serverBuf, cbMaxToken);
try
done := False;
try
// Prepare client message (negotiate)
cbOut := cbMaxToken;
ss := Self.GenClientContext(#asClient, authIdentity, packageName, nil, 0, clientBuf, cbOut, done);
if ss < 0 then
begin
RaiseWin32Error('Error generating client context for negotiate', ss);
Result := ss;
Exit;
end;
// Prepare server message (challenge).
cbIn := cbOut;
cbOut := cbMaxToken;
ss := Self.GenServerContext(#asServer, packageName, clientBuf, cbIn, serverBuf, cbOut, done);
if ss < 0 then
begin
{
Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED in the case of bad username or password.
Unexpected Result: Logon will succeed if you pass in a bad username and the guest account is enabled in the specified domain.
}
RaiseWin32Error('Error generating server message for challenge', ss);
Result := ss;
Exit;
end;
// Prepare client message (authenticate).
cbIn := cbOut;
cbOut := cbMaxToken;
ss := Self.GenClientContext(#asClient, authIdentity, packageName, serverBuf, cbIn, clientBuf, cbOut, done);
if ss < 0 then
begin
RaiseWin32Error('Error generating client client for authenticate', ss);
Result := ss;
Exit;
end;
// Prepare server message (authentication).
cbIn := cbOut;
cbOut := cbMaxToken;
ss := Self.GenServerContext(#asServer, packageName, clientBuf, cbIn, serverBuf, cbOut, done);
if ss < 0 then
begin
RaiseWin32Error('Error generating server message for authentication', ss);
Result := ss;
Exit;
end;
finally
//Free resources in client message
if asClient.fHaveCtxtHandle then
sspi.DeleteSecurityContext(#asClient.hctxt);
if asClient.fHaveCredHandle then
sspi.FreeCredentialHandle(#asClient.hcred);
//Free resources in server message
if asServer.fHaveCtxtHandle then
sspi.DeleteSecurityContext(#asServer.hctxt);
if asServer.fHaveCredHandle then
sspi.FreeCredentialHandle(#asServer.hcred);
end;
finally
FreeMem(clientBuf);
FreeMem(serverBuf);
end;
Result := S_OK;
end;
Note: Any code released into public domain. No attribution required.
There is a win32 API function called ldap_bind_s. The ldap_bind_s function authenticates a client
against LDAP. See MSDN documentation for more information.
I authenticated user, by username & password like this :
username is user sn attribute value in Ldap server, like U12345
userDN is user DistinguishedName in LdapServer
public bool AuthenticateUser(string username, string password)
{
try
{
var ldapServerNameAndPort = "Servername:389";
var userDN = string.Format("CN=0},OU=Users,OU=MyOU,DC=MyDC,DC=com",username);
var conn = new LdapConnection(ldapServerNameAndPort)
{
AuthType = AuthType.Basic
};
conn.Bind(new NetworkCredential(userDN , password));
return true;
}
catch (Exception e)
{
return false;
}
}

Resources