Getting the field issuedFor from SecurityIdentity using OIDC and KeyCloak - keycloak

I am using OIDC and KeyCloak Quarkus extensions.
Currently, I access the token information like this:
#Inject org.eclipse.microprofile.jwt.JsonWebToken tokenMicroProfile;
#Inject SecurityIdentity securityIdentity;
I could not find the issuedFor field in these abstractions. This seems to have what I need.
#Inject org.keycloak.representations.JsonWebToken tokenKeyCloak;
But injection fails. So, how can I get the information using quarkus-oidc?

You can do tokenMicroProfile.getClaim("azp") or tokenMicroProfile.getClaim(Claims.azp).

Related

How to get the list of all User Federation Providers associated with a realm?

I am using Keycloak 11.0 and looking for an approach to get all the user federation providers associated to a given Realm. On my setup I have created a dummy Realm and added to it a dummy Federation.
I used the Keycloak Admin Rest API to get the Realm and then looking into the json userFederationProviders field, but nothing is there. I have also tried with the following Java code:
import org.keycloak.admin.client.Keycloak;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserFederationProviderRepresentation;
public class Key {
public static void main(String[] args){
Keycloak keycloak = Keycloak.getInstance(
"http://localhost:8080/auth/",
"dummyRealm",
"admin",
"a",
"admin-cli");
RealmRepresentation realm = keycloak.realm("dummyRealm").toRepresentation();
for(UserFederationProviderRepresentation s : realm.getUserFederationProviders())
System.out.println(s.getDisplayName());
}
}
However, I get a NPE because the realm.getUserFederationProviders() is null.
Is there any way to get the list of all userFederationProviders associated to a Realm without having to use the Keycloak Admin console?
List realm components and filter type=org.keycloak.storage.UserStorageProvider&parent=<realm name>. Check browser network console and you will see that this API request is also made by Keycloak Admin console, when you visit User Federation configuration.

Keycloak: missing realm public key

when I access keycloak admin console (!remotely) and create client:
the keycloak OIDC JSON doesn't have public key
I would expect having in JSON something like:
"realm-public-key": "MIIBIjANBg....
keycloak.json in newest keycloak doesnot have any realm public key ... actually it appears that you are using keycloak version 2.3.x there have been some changes in it . Basically you can rotate multiple public keys for a realm . The document says this :-
In 2.3.0 release we added support for Public Key Rotation. When admin
rotates the realm keys in Keycloak admin console, the Client Adapter
will be able to recognize it and automatically download new public key
from Keycloak. However this automatic download of new keys is done
just if you don’t have realm-public-key option in your adapter with
the hardcoded public key. For this reason, we don’t recommend to use
realm-public-key option in adapter configuration anymore. Note this
option is still supported, but it may be useful just if you really
want to have hardcoded public key in your adapter configuration and
never download the public key from Keycloak. In theory, one reason for
this can be to avoid man-in-the-middle attack if you have untrusted
network between adapter and Keycloak, however in that case, it is much
better option to use HTTPS, which will secure all the requests between
adapter and Keycloak.
I still don't know why there is no public key in keycloak OIDC JSON (probably from security reason), but I have found it under:
Realm Settings > Keys > Public Key View
I had this same problem initially, but then figured out that I was using the wrong URL. The OpenID config is published by Keycloak under this URL, as per the standard:
http://localhost:8080/auth/realms/myrealm/.well-known/openid-configuration
But the public key is published under the jwks_uri, which is this:
http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/certs
Using that second URL, it is quite easy to validate the JWT using the connect2id library (https://connect2id.com/products/nimbus-jose-jwt/examples/validating-jwt-access-tokens):
...
JWT idToken = JWTParser.parse(bearerAccessToken.toString());
Nonce expectedNonce = null;
Issuer iss = new Issuer("http://localhost:8080/auth/realms/myrealm");
JWSAlgorithm jwsAlg = JWSAlgorithm.RS256;
URL jwkSetURL = new URL("http://localhost:8080/auth/realms/myrealm/protocol/openid-connect/certs");
IDTokenValidator validator = new IDTokenValidator(iss, clientID, jwsAlg, jwkSetURL);
IDTokenClaimsSet claims = validator.validate(idToken, expectedNonce);
...

how to get HTTP request object in class implementing jackrabbit ExternalIdentityProvider

I am implementing custom external identity provider and to do this I need to implement ExternalIdentityProvider class from jackrabbit.
http://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html
In normal case you would need to pass j_username and j_password and you can get these from values SimpleCredentials object
My question is that since I need to pass additional form parameter say for instance linkedin ID in my case, how do I achieve that?
#Component(
policy = ConfigurationPolicy.REQUIRE
)
#Service
public class RDBMSIdentityProvider implements ExternalIdentityProvider {
#Override
public ExternalUser authenticate(Credentials credentials)
throws ExternalIdentityException, LoginException {
//i can get username / password from credentials object
//how to get additional parameters from http request object?
}
Any input is highly appreciated.
Thanks!
The correct way to handle this is to have a custom AuthenticationHandler which creates an instance of a specific Credentials object with whatever parameters you need in it.
That said, if you are integrating with LinkedIn (and this is in AEM), you would be better served by integrating with the existing OAuth AuthenticationHandler. There is OOTB support for Facebook and Twitter, but the OAuth provider is designed to be pluggable for different OAuth Service Providers.

Spring MVC authorization in REST resources

I have REST api for accessing "parties" and the URL's look like this:
/parties
/parties/{partyId}
Using Spring controllers and #PathVariable I'm able to implement this interface. But to prevent users from accessing parties they don't have access to, I have to add checks to every method call which is kind of repeating myself and I might forget to add it everywhere:
#RequestMapping(value="/parties/{partyId}", method=RequestMethod.GET)
public #ResponseBody Party getParty(#PathVariable Integer partyId){
authorizeForParty(partyId);
...
Now what I would like to do is create a check that would be called every time that user enters url like this:
/parties/{partyId}/**
How would I do something like this? Do I have to create some servlet filter and parse the url myself? If I have to parse the url then is there atleast tools that would make it easy? I wish there was a way to add a method to controller that would be called before methods but could still use #PathVariables and such...
What I ended up with is using the Spring MVC interceptors and parsing the path variables in the same way that Spring does. So I define an interceptor for the REST url:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/parties/*/**" />
<bean class="PartyAuthorizationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
The PartyAuthorizationInterceptor has to implement HandlerInterceptor in which we have to implement preHandle. It has HttpServletRequest as a parameter so we can get the request URL but we still have to parse the partyId from the url. After reading how Spring MVC does it, I found out they have a class named org.springframework.util.AntPathMatcher. It can read the path variables from the URL and place the values in a map. The method is called extractUriTemplateVariables.
So the result looks like this:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String partyIdStr = new AntPathMatcher().extractUriTemplateVariables("/parties/{partyId}/**", request.getPathInfo()).get("partyId");
...
That makes the parsing almost as easy as using #PathVariable in MVC Controller methods. You still have to do conversions yourself(e.g. String -> Integer).
Now I can implement authorization logic on all urls that access a party in this interceptor and keep that logic out of the individual controller methods. Not as easy as I would have hoped but it gets the job done.
Are you already using some kind of security library in your application, e. g. Spring Security?
Because the kind of logic you want to implement is a classic case for an AccessDecisionVoter in an authentication chain. You would just put your API behind Spring Security's protection and implement the custom check as part of the security chain.
If you are not using a security framework at all, your idea of implementing a HandlerInterceptor may be the best alternative, though. But it would require you (as you mentioned) to take into account all kinds of obfuscation the user may use in order to gain access to other URLs (e. g. %-encoding of letters, ../../ patterns etc.).

ASP.NET Web API Authorization with AuthorizeAttribute

Using the new ASP.NET Web API beta. I can not seem to get the suggested method of authenticating users, to work. Where the suggested approach seems to be, to add the [Authorize] filter to the API controllers. For example:
[Authorize]
public IEnumerable<Item> Get()
{
return itemsService.GetItems();
}
This does not work as intended though. When requesting the resource, you get redirected to a login form. Which is not very suitable for a RESTful webapi.
How should I proceed with this? Will it work differently in future versions?, or should I fall back to implementing my own action filter?
Double check that you are using the System.Web.Http.AuthorizeAttribute and not the System.Web.Mvc.AuthorizeAttribute. This bit me before. I know the WebAPI team is trying to pull everything together so that it is familiar to MVC users, but I think somethings are needlessly confusing.
Set your authentication mode to None:
<authentication mode="None" />
None Specifies no authentication. Your application expects only anonymous users or the application provides its own authentication.
http://msdn.microsoft.com/en-us/library/532aee0e.aspx
Of course then you have to provide some sort of authentication via headers or tokens or something. You could also specify Windows and use the built in auth via headers.
If this site is mixed between API and actual pages that do need the Forms setting, then you will need to write your own handling.
All the attribute does is return an HttpUnauthorizedResult instance, the redirection is done outside of the attribute, so its not the problem, its your authentication provider.
Finally, I've found a solution at:
ASP.NET MVC 4 WebAPI authorization
This article shows how you can fix this issue.
You are being redirected to login page because forms authentication module does this automatically. To get rid of that behavior disable forms authentication as suggested by Paul.
If you want to use more REST friendly approach you should consider implementing HTTP authorization support.
Take a look at this blog post http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/
ASP.NET 5 Introduced the new Microsoft.AspNet.Authorization System which can secure both MVC and Web API controllers.
For more see my related answer here.
Update:
At that time 2 years ago it was Microsoft.AspNetCore.Authorization.
As #Chris Haines pointed out. now it resides on
Microsoft.AspNetCore.Authorization.
From .NET core 1.0 to 2.0 many namespaces have been moved i think.
And spread functionality between .net classic and core was obscure.
That's why Microsoft introduced the .net standard.
.net standard
Also, look at my answer for:
How to secure an ASP.NET Web API
There is a NuGet package I have created which you can use for convenience.
If you're using a Role, make sure you have it spelled correctly :
If your role is called 'Administrator' then this - for instance will not work :
[System.Web.Http.Authorize(Roles = "Administator")]
Neither will this :
[System.Web.Http.Authorize(Roles = "Administrators")]
Oops...
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Produces("application/json")]
[Route("api/[controller]")]
public class CitiesController : Controller
{
[HttpGet("[action]")]
public IActionResult Get(long cityId) => Ok(Mapper.Map<City, CityDTO>(director.UnitOfWork.Cities.Get(cityId)));
}
Use
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Filter with authentication type