Out of the tokens issued by Thinktecture IdentityServer4, there is one called sid - the session id. In my application, I would like to link this id with some of my other logics. But I am not sure if I can assume it's always a GUID string. I tested a few. They are all valid GUIDs. Just wondering if my assumption is right.
I looked into the source code of IdentityServer4 and found out the sid is generated by:
public static string CreateUniqueId(int length = 16)
{
var bytes = new byte[length];
new RNGCryptoServiceProvider().GetBytes(bytes);
return ByteArrayToString(bytes);
}
According to this link, the result can be parsed as a GUID.
Related
Some Background
In asp.net core when using SqlServer to store sessions, oddly enough the Id column in the SqlServer table gets set to the value of sessionKey which is a Guid generated by the SessionMiddleware. I say oddly enough because there is a SessionId but the Id in the table isn't set to that, it is set to the SessionKey. (I'm not making this up)
This sessionKey used for the Id in the table is also the value that is encrypted and placed in the session cookie. Here is that SessionMiddleware code:
var guidBytes = new byte[16];
CryptoRandom.GetBytes(guidBytes);
sessionKey = new Guid(guidBytes).ToString();
cookieValue = CookieProtection.Protect(_dataProtector, sessionKey);
var establisher = new SessionEstablisher(context, cookieValue, _options);
tryEstablishSession = establisher.TryEstablishSession;
isNewSessionKey = true;
The SessionId however, is a Guid generated by the DistributedSession object in the following line of code:
_sessionId = new Guid(IdBytes).ToString();
Interestingly the ISession interface provides a property for the SessionId but not the SessionKey. So it's often much easier in code to get access to a SessionId then a SessionKey, for example when you have access to an HttpContext object.
This makes it hard to match up the session to the database record if you desire to do that. This was noted by another user on stackoverflow as well How to Determine Session ID when using SQL Sever session storage.
Why?
What I want to know is why is the system designed this way? Why isn't the SessionId and SessionKey the one and the same? Why use two different Guids? I ask because I'm creating my own implementation of ISession and I'm tempted to use the SessionKey as the SessionId in my implementation so that it's easier to match up a record in the database to a session. Would that be a bad idea? Why wan't DistributedSession object designed that way rather than generating a SessionId that is different than the SessionKey? The only reason I can think of is perhaps trying increase security by obfuscating the linkage between the database record and the session it belongs to. But in general security professionals don't find security through obfuscation effective. So I'm left wondering why such a design was implemented?
I also posted the question on GitHub https://github.com/aspnet/Session/issues/151#issuecomment-287894321 to try to get an answer as well.
#Tratcher answered the question there so I'm pasting his answer below so that it's available here on stackoveflow too.
The lifetimes are different. The true lifetime of a session (and SessionId) is controlled by the server. SessionKey is stored in the cookie and lives on the client for an indeterminate amount of time. If the session expires on the server and then the client sends a new request with the old SessionKey, a new session instance with a new SessionId is created, but stored using the old SessionKey so that we don't have to issue a new cookie.
Put another way, don't depend on things outside of your control. The client can keep and replay their SessionKey indefinitely, but it's the server that decides if that is really still the same session.
In case someone need to get the sessionkey in asp.net core 3
Add DI for IDataProtector (IMPORTANT! when create protector it should be nameof(SessionMiddleware))
public IDataProtector _dataProtector;
public TestController( IDataProtectionProvider dataProtectionProvider )
{
_dataProtector = dataProtectionProvider.CreateProtector(nameof(SessionMiddleware));
}
Create method which will get proper value for the session cookie
private string Pad(string text)
{
var padding = 3 - ((text.Length + 3) % 4);
if (padding == 0)
{
return text;
}
return text + new string('=', padding);
}
Use it
public ActionResult TestSession( )
{
var protectedText = HttpContext.Request.Cookies[ ".AspNetCore.Session" ];
var sessionKey = "";
var protectedData = Convert.FromBase64String(Pad(protectedText));
if (protectedData == null)
{
sessionKey = string.Empty;
}
var userData = _dataProtector.Unprotect(protectedData);
if (userData == null)
{
sessionKey = string.Empty;
}
sessionKey = Encoding.UTF8.GetString(userData);
return Content( sessionKey );
}
How do you generate an Id in App engine datastore automatically?
I am using the automatically created Backend Function insertEntity().
As primary key I am using
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long Id;
And when I call the insert function I would like that the datastore automatically assigns this Id...
Thanks.
Technically, there is nothing wrong with what you have done. The ID will get generated automatically.
The problem I believe is the Auto Generated code that has been generated for the insertEntity() method. The code currently expects that the ID value has been provided and based on that, it first tries to retrieve an existing Entity. Since the ID is most likely null i.e. you have not passed it, it is resulting in an exception in the code.
Modify the code to check if the getId() != null. If not null, only then allow it to go forward, else just invoke the makePersistent() code.
Good morning I'm trying to integrate the Google+ Domains API with my company domain but I'm facing some problems.
I'm trying the java approach following the quick start for java but after implement the code the response from the google server is :
Authenticate the domain for hugo.catarino#outsystems.com
Inserting activity
10/Set/2013 17:08:49 com.google.api.client.googleapis.services.AbstractGoogleClient <init>
WARNING: Application name is not set. Call Builder#setApplicationName.
Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException:400 Bad Request
{
"error" : "access_denied"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:269)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:858)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.google.plus.samples.quickstart.domains.DomainDelegation.main(DomainDelegation.java:160)
here is used authentication method and my variables:
private static final String SERVICE_ACCOUNT_EMAIL = "638852846577#developer.gserviceaccount.com";
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
"src/com/google/plus/samples/quickstart/domains/05cab8e819cbd0a747b180c1f22fc93dba916b7b-privatekey.p12";
private static final String USER_EMAIL = "hugo.catarino#outsystems.com";
private static Plus authenticate() throws GeneralSecurityException, IOException {
System.out.println(String.format("Authenticate the domain for %s", USER_EMAIL));
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
// Setting the sub field with USER_EMAIL allows you to make API calls using the special keyword
// 'me' in place of a user id for that user.
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPE)
.setServiceAccountUser(USER_EMAIL)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH)).build();
// Create and return the Plus service object
Plus service = new Plus.Builder(httpTransport, jsonFactory, credential).build();
return service;
}
My main class has the following code like in the sample:
Plus service = authenticate();
String userId = "me";
String msg = "Happy Monday! #caseofthemondays";
System.out.println("Inserting activity");
// Create the audience of the post
PlusAclentryResource res = new PlusAclentryResource();
// Share to the domain
res.setType("domain");
List<PlusAclentryResource> aclEntries = new ArrayList<PlusAclentryResource>();
aclEntries.add(res);
Acl acl = new Acl();
acl.setItems(aclEntries);
// Required, this does the domain restriction
acl.setDomainRestricted(true);
Activity activity = new Activity()
.setObject(new Activity.PlusObject().setOriginalContent(msg))
.setAccess(acl);
activity = service.activities().insert(userId, activity).execute();
System.out.println(activity);
In domain cPanel the company defined for me the next scopes:
https://www.googleapis.com/auth/plus.circles.read
https://www.googleapis.com/auth/plus.circles.write
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/plus.media.upload
https://www.googleapis.com/auth/plus.stream.read
https://www.googleapis.com/auth/plus.stream.write
My scope definition is:
private static final List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.circles.read",
"https://www.googleapis.com/auth/plus.circles.write",
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.media.upload",
"https://www.googleapis.com/auth/plus.stream.read",
"https://www.googleapis.com/auth/plus.stream.write");
I'm a bit lost here , is there any way of debug this problem or know why is this access denied?
There are several things that you should check.
First, is the private key file that you downloaded from the Google APIs Console in the correct path with your code? This file is referenced by the following variable. This needs to tell the OAuth client library where to find the file.
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH =
"/path/to/<public_key_fingerprint>-privatekey.p12";
It is very important that you do not rename the file.
Second, does your scope list in your code match the list of scopes set in the Admin console?
The configuration in the Admin console for your Google Apps domain, and the scopes provided in the request must be identical. Try adjusting the SCOPE variable in your code to be:
private static final List<String> SCOPE = Arrays.asList(
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.circles.read",
"https://www.googleapis.com/auth/plus.circles.write",
"https://www.googleapis.com/auth/plus.media.upload",
"https://www.googleapis.com/auth/plus.stream.read",
"https://www.googleapis.com/auth/plus.stream.write");
In general, it is best to only request the scopes that you will need, rather than all scopes available.
Third, make sure that the client ID you generated is the one listed on the Admin console entry that specifies the scopes permitted.
I have generated a self signed certificate using the CertCreateSelfSignCertificate function. This yields a PCCERT_CONTEXT.
How can I export the certificate stored in the PCCERT_CONTEXT variable with only the public key? I want to do this, to send it to other parties in the network, so these are able to encrypt messages using the public key.
I thought this was a straight forward option, but it isnt.
No need for a pfx.
The certificate is present inside the structure CERT_CONTEXT : just save the content of the buffer pointed by the member pbCertEncoded and whose length is the value of the member cbCertEncoded.
Moreover, the public key from this certificate is directly present in the CERT_CONTEXT structure : pCertInfo->SubjectPublicKeyInfo. For example, you can import it using CryptImportPublicKeyInfo and then call CryptEncrypt to encrypt data.
With these two options, you have all what is needed to start encrypting messages. Of course, the private key must be kept safe to be able to decrypt encrypted data.
Looks like you will need to first put the certificate into a certificate store and then export it using PFXExportCertStoreEx passing dwFlags of 0 (i.e. not setting EXPORT_PRIVATE_KEYS).
P.S. nothing is ever straight forward when dealing with cryptography libraries, be it CryptAPI, JSSE, OpenSSL... it's always a nightmare.
Hope you can help.
I'm trying to copy a blob using the Protocol namespace along with a shared access signature, but the WebResponse always throws a 404 Not Found error. I have successfully used the Get/Post/Delete/List methods (where the 404 would be thrown if the permissions were insufficient), but I cannot find the answer here.
Here's some simple code that I am using:
Uri uriFrom = new Uri("file://mymachine/myfile.txt");
Uri uriTo = new Uri("file://mymachine/myfile1.txt");
//get shared access signature - set all permissions for now
uriTo = GetSharedAccessSignature(uriTo, SharedAccessPermissions.Write |
SharedAccessPermissions.Read | SharedAccessPermissions.List);
//NOTE: This returns my uriTo object in the following format:
//http://mystoragespace.blob.core.windows.net/mycontainer/steve1.txt?se=2011-07-04T12:17:18Z&sr=b&sp=rwdl&sig=sxhGBkbDJpe9qn5d9AB7/d2LK1aun/2s5Bq8LAy8mis=
//get the account name
string accountName = uriTo.Host.Replace(".blob.core.windows.net", string.Empty);
//build the canonical string
StringBuilder canonicalName = new StringBuilder();
canonicalName.AppendFormat(System.Globalization.CultureInfo.InvariantCulture,
"/{0}/mycontainer{1}", accountName, uriFrom.AbsolutePath);
//NOTE: my canonical string is now "/mystoragespace/mycontainer/myfile.txt"
//get the request
var request = BlobRequest.CopyFrom(uriTo, 300, canonicalName.ToString(),
null, ConditionHeaderKind.None, null, null);
request.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
//perform the copy operation
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
//do nothing. the file has been copied
}
So, my uriTo seems to have the appropriate permissions (I've tried various combinations) and the canonical string seems to have the correct source string. I'm not using snapshot functionality. The proxy isn't a problem as I've successfully used other methods.
Hope someone can help...
Many regards,
Steve
From Creating a Shared Access Signature:
The following table details which operations are allowed on a resource for a given set of permissions.
...
Create or update the content, block list, properties, and metadata of the specified blob. Note that copying a blob is not supported.