How to get client_id value in ADFS Issuance Transform Rule - oauth-2.0

I am implementing a client credentials grant in ADFS3.0. This works based on the scenarios and developer examples.
I want to add an issuance transform rule that uses the client_id to lookup extra claims in a custom sql attribute store.
c:[Type == "???"]
=> issue(store = "Custom Attribute Store", types = ("XYZ"), query = "SELECT claimValue from dbo.ClientClaims WHERE clientId= {0}", param = c.Value);
What is the correct value for Type to find the client_id?

You can retrieve the appid using the following:
appid:[Type == "http://schemas.microsoft.com/2014/01/clientcontext/claims/appid"]
This will grant you access to the appid (The 36 character identifier for your client) to use in your custom rule.

Claims work off AD and clientID is not an AD attribute.
The only way I can think of is to use a static claim where the clientID is hard-coded with a Type like "http://company.com/clientID" and then use that in the above rule.

Related

How does an OAuth2 server obtain launch context for smart on FHIR?

I am integrating a Smart on FHIR app that will be launched from within an EHR. When the user clicks a button to launch the app, we set a GUID and the current Patient ID to a database record on our FHIR server. The assumption being that given the 'Launch' scope, the OAuth server will call the appropriate API to retrieve the Patient ID given that the GUID is included in the url params.
The call to auth looks like this:
_clientID = {the unique client ID registered to our auth server}
_redirectURL = {redirect back to auth for eventual token request}
launch={the GUID value generated at start of the session and paired with the Patient ID}
_scopes = "launch patient/*.* openid profile"
state = {some opaque value}
aud = {the base URL for our FHIR server}
string url = $"{authorizeURL}?response_type=code&client_id={_clientID}&" +
$"redirect_uri={_redirectURL}&" +
$"launch={launch}&" +
$"scope={HttpUtility.UrlEncode(_scopes)}&" +
$"state={state}&" +
$"aud=https://xxx-smart.xxxxxxxxx.com";
All of this works and I end up with a json response that includes the id_token, access_token, expires_in, token_type('Bearer'). But, no 'patient'.
My assumption was that the OAuth server would call the scope 'launch/patient' on our FHIR server but no such call is being made. In fact, I created a few endpoints just for the purpose of logging and NONE of them are being called.
Here is an example of one of my FHIR Server test/log endpoints (I created few with 1 to 4 parameters):
[AllowAnonymous]
[HttpGet("{functionName}/{id}")]
public string GetPatientData3(string functionName, string id)
{
TelemetryClient telemetry = new();
telemetry.TrackEvent($"FHIR SVR GetPatientData3 {functionName} {id}");
string configJson = "0009998888";
return configJson;
}
How do I set this 'patient' context properly?
How does the OAuth server retrieve this context so I can have that patient ID appear in the json response from the ~/token call?
Further Notes:
The contents of the openid-configuration:
{"token_endpoint":
"https://aadproxy.azurewebsites.net/xxx/oauth2/v2.0/token",
"token_endpoint_auth_methods_supported":
["client_secret_post","private_key_jwt","client_secret_basic"],
"jwks_uri":
"https://login.microsoftonline.com/xxx/discovery/v2.0/keys",
"response_modes_supported": ["query","fragment","form_post"],
"subject_types_supported": ["pairwise"],
"id_token_signing_alg_values_supported": ["RS256"],
"response_types_supported":["code","id_token","code
id_token","id_token token"],
"scopes_supported":["openid","profile","email","offline_access"],
"issuer": "https://login.microsoftonline.com/xxx/v2.0",
"request_uri_parameter_supported":false,
"userinfo_endpoint":"https://graph.microsoft.com/oidc/userinfo",
"authorization_endpoint":
"https://aadproxy.azurewebsites.net/xxx/oauth2/v2.0/authorize",
"device_authorization_endpoint":
"https://login.microsoftonline.com/xxx/oauth2/v2.0/devicecode",
"http_logout_supported":true,
"frontchannel_logout_supported":true,
"end_session_endpoint":
"https://login.microsoftonline.com/xxx/oauth2/v2.0/logout",
"claims_supported":
["sub","iss","cloud_instance_name","cloud_instance_host_name",
"cloud_graph_host_name","msgraph_host","aud","exp","iat",
"auth_time","acr","nonce","preferred_username",
"name","tid","ver","at_hash","c_hash","email"],
"kerberos_endpoint":
"https://login.microsoftonline.com/xxx/kerberos",
"tenant_region_scope":"NA",
"cloud_instance_name":"microsoftonline.com",
"cloud_graph_host_name":"graph.windows.net",
"msgraph_host":"graph.microsoft.com",
"rbac_url":"https://pas.windows.net"}
So, I notice that the 'patient/.' and the 'launch' scope among a whole host of others that I have are not supported according to my openid config. The only supported ones are "openid","profile","email", "offline_access".
In Azure AD, 'App Registration' > 'Expose an API' I have a list of at least 15 scopes entered there. In 'API' permissions they are all listed there as well.
One other thing to note, AzureAD does not handle scopes with a forward slash. So, launch/patient has to be entered as launch-patient. We also had to implement a proxy server to capture the ~/oauth2/v2.0/authorize request and modify the scope parameter entries to reflect this before passing on the request to the actual server.
I guess the pertinent question now is: How do the scopes that I have entered manually get supported?

Websphere 8.5.5.16, OIDC IDToken - user problem

I'm trying to configure Oauth authorization on websphere 8.5.5.16. I added interceptor with issuerIdentifier parameter = https://company.com/abc I next step I added trust external realm: https://company.com/abc And when I try to start service in my app (IBM BPM) I getting an error: NullPointer Exception. Please look at the logs on how the user is created:
Principal: https://company.com/abc/login_user
Public Credential: com.ibm.ws.security.auth.WSCredentialImpl#ebc4e0d2
Private Credential: {setLtpaCookie=false, com.ibm.wsspi.security.cred.securityName=login_user, com.ibm.wsspi.security.cred.uniqueId=user:https://company.com/abc/login_user, token_type=, access_token=xxx, id_token=, com.ibm.wsspi.security.cred.realm=https://company.com/abc, com.ibm.wsspi.security.cred.groups=[], refresh_token=, JsonWebToken=JsonWebToken:{"aud":"0000","iss":"https://company.com/abc","iat":122,"nbf":123,"exp":232,"auth_time":222,"nonce":"aaa","sub":"ddddd/fffff","upn":"login_user","unique_name":"domain\\login_user","pwd_url":"https://company.com/abc/portal/updatepassword/","pwd_exp":"4545","sid":"S-1-5-21-66-117609710","authorities":["Group_1, Group_2"],"given_name":"Name","family_name":"Surname","apptype":"Public","appid":"0000","authmethod":"http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/windows","ver":"1.0","scp":"openid"}}
Private Credential: com.ibm.ws.security.token.SingleSignonTokenImpl#347c9d2b
Private Credential: com.ibm.ws.security.token.AuthenticationTokenImpl#718ea698
Private Credential: com.ibm.ws.security.token.AuthorizationTokenImpl#27e8a5bb
00000187 UserOrgModule 1 com.lombardisoftware.userorg.UserOrgModule getIdFromPrincipalName getIdFromPrincipalName() user=/company.com/abc/login_user, id=null
user = /company.com/abc/login_user not: login_user Why? Please help.
From message "00000187 UserOrgModule", I can tell your BPM application can not help realm name that contains '/' character. You can resolve the problem with following steps:
In your TAI properties, add useRealm property, and give an unique and meaningful value as realm, for example,
provider_.useRealm=abc123
Add "abc123" as trusted realm. This value matches value you define in step 1.
If you assign roles to users unique id, you need reassign roles again with unique id build from this new realm.
Thanks. I did exactly as you wrote.
I added in my interceptor config: provider_1.useRealm=myrealm
I added trusted realm in Global security > Federated repositories > Trusted authentication realms - inbound (Name = myrealm, Trusted).
I restarted server.
Nothing has changed. I still see: user=/company.com/abc/login_user, id=null because in JWT token, in iss field I have value: 'https://company.com/abc' and unfortunately I cannot change this

Client credentials grant generate tokens for lifetime

I am creating an API in laravel a using two grants [password, client_credentials] and I want to configure token lifetime for separate for both grants.
If I configure token lifetimes according to laravel passport documentation then its set's for both grants.
I need help to configure separate lifetime for both grants.
Create the access token with $token = $user->createToken('API Access') and use a query with DB::table('oauth_access_tokens')->where('id', $token->id)->update([...]) to change the value of 'expires_at' manually.
Apply same on 'oauth_refresh_tokens' with ->where('access_token_id', $token->id)
In the boot function of your AuthServiceProvider you can still check the value of grant_type in your request to define different lifetime.
if($request["grant_type"] === "client_credentials"){
// If token is a client_credential we define it to one year
Passport::tokensExpireIn(Carbon::now()->addYear());
}else{
// Or we define it to only one hour
Passport::tokensExpireIn(Carbon::now()->addHour());
}

How to get the value of access token in ASP.NET Core MVC OAuth 2.0

In Visual Studio 2017RC I created ASP.NET Core MVC app with individual user accounts and successfully completed https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins tutorial to attach Google authentication. I'm now logged in via my Google account.
All I did was adding a few lines to the autogenerated code (in Configure method of Startup.cs):
app.UseGoogleAuthentication(new GoogleOptions
{
ClientId = "xxxx.apps.googleusercontent.com",
ClientSecret = "xxxx",
Scope = { "email", "openid" }
});
I now need to get the value of access token which was issued by Google (and stored in cookies by the app). I'll then use it to generate XOAuth2 key to access Google services. For instance, in HomeController's About method (auto-generated by the standard wizard) I want to display the number of unread emails in my inbox. With XOAuth2 key, I can log in my Gmail and proceed from here.
How can I get this token?
- Do I need to store access token in database during initial logging in via Google? If so, any clues how this can be done in the standard wizard-generated ASP.NET Core MVC app?
- Or, maybe I can always read the access token from cookies? If so, how?
Preferably, I'd read it from cookies (it's anyway there) and avoid duplicating this info in database but not sure if this approach is feasible (i.e. if it can be decrypted).
I did this for ASP.NET MVC once but in ASP.NET Core MVC things have changed a lot, the legacy code is of no use anymore.
OK, found it. SaveTokens property does the trick.
app.UseGoogleAuthentication(new GoogleOptions
{
ClientId = "xxxx.apps.googleusercontent.com",
ClientSecret = "xxxx",
Scope = { "email", "openid" },
SaveTokens = true,
AccessType = "offline"
});
I can then get access token in AccountController.ExternalLoginCallback
var token = info.AuthenticationTokens.Single(x => x.Name == "access_token").Value;

Attempting to log in using Google account in cfoauth tag

I am trying to login using the <cfoauth> tag, but am not able to do so. It is showing
Error: invalid_request
Below is my code.
<cfoauth
type = "google"
clientid = "*****************es7t0r6qc"
secretkey = "**************tSF97WncM5ix9jtvD200"
result = "result"
scope="https://www.googleapis.com/auth/plus.me"
redirecturi = "http://192.168.9.126:8088/bootstrap-blog-template/tpl/cfoauth.cfm"
>
Please help.
The problem seems to be related to redirecturi. You need to provide an existing and valid URL of the page on which you want to redirect to after authentication.
For example if local URL of the page you are testing the code is http://localhost:8500/cfbuster/login.cfm , then redirecturi can be same page i.e. http://localhost:8500/cfbuster/login.cfm or another page http://localhost:8500/cfbuster/doLogin.cfm.
Apart from this, the redirecturi you wish to set, should be saved in Google Developers Consele >> API Manager >> Credentials screen under Authorized redirect URIs. In my case it is http://localhost:8500/cfbuster/test.cfm
In case the redirecturi passed is non existing or not saved in the API Authorized redirect URIs screen we get following error message:
Note 1: The redirecturi Must have a protocol. Cannot contain URL fragments or relative paths. Cannot be a public IP address.
Note 2: https://www.googleapis.com/auth/plus.login is the recommended login scope. The https://www.googleapis.com/auth/plus.me scope is not recommended as a login scope because, for users who have not upgraded to Google+, it does not return the user's name or email address.

Resources