How do I use application’s auth identity in Apigility? - zend-framework2

My authentication use-case is fairly simple. I use my API only myself in the frontend of my ZF application, when a user is logged in. So any of the provided Authentication Adapters seem overkill to me. I don’t need the API to ask for credentials at all.
I want to use the identity provided in the browser’s session. If the user is logged in, the API should be accessible, otherwise not.
So I guess what I have to to, is to somehow inject the application’s auth adapter or identity into the Apigility API module.
My app uses ZfcUser and ZfcRbac to manage roles and identities.

This really seems to be hard to achieve, since Apigility uses own identity models provided by zf-mvc-auth, which are not compatibly with ZfcUser’s identities. So simply switching the authentication service didn’t do the job.
I now found a solution, albeit an unflexible one. In my application’s Module.php I attach an event listener to the EVENT_AUTHORIZATION event of zf-mvc-auth and simply modify the authorized state of the event itself.
Not very cool, but works as long as you have to distinguish between guest status and everything else. Roles don’t work this way.
public function onBootstrap(MvcEvent $e)
{
$serviceManager = $e->getApplication()->getServiceManager();
$eventManager->attach(
MvcAuthEvent::EVENT_AUTHORIZATION,
function(MvcAuthEvent $mvcAuthEvent) use ($serviceManager)
{
$authService = $serviceManager->get('Zend\Authentication\AuthenticationService');
if ($authService->hasIdentity()) {
$mvcAuthEvent->setIsAuthorized(true);
}
},
100
);
}

Related

Add 'ROLE' to spring security / Auth0 authorization

In my Spring Boot application i'm working with Auth0 to manage access to my rest api.
In addition to Auth0's scope i would like to add a ROLE to each user which in turn will provide an additional layer of access control where specific API's won't be accessible to low privileged users.
I've been reading about custom rules and authorization extensions but couldn't quite understand what is the right implementation for me.
Here's my WebSecurityConfigurerAdapter code snippet:
So basically i want only 'ADMIN' for example to be able to access /test/**
#Override
protected void configure(HttpSecurity http) throws Exception {
JwtWebSecurityConfigurer
.forRS256(configBean.getAuth0ApiAudience(), configBean.getAuth0Issuer())
.configure(http)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/test/**").hasAuthority("read:test")
.anyRequest().authenticated();
}
Any help would be much appreciated!
You have a few options here (at least..).
1). You could conceivably use a Rule to do handle the decision logic on which "ROLES" are assigned to given user - and rather than tag this onto scope (which you could do too..), you may decide they belong instead as a custom claim on that access token. Body of Rule may contain something like
// lookup the permissions for given user somehow (secured webhook, static map etc) - here lets imagine we want ROLE_USER assigned
context.accessToken.scope = "ROLE_USER"
// or
context.accessToken['https://mydomain/roles'] = "ROLE_USER"
2). Simply use the fact that you have the auth0 userid available in the JWT Access token from Auth0 that you send to the API - you could use this knowledge to look up the finer grained permissions for that use "out of bands" of Auth0 (using your own database storage for permissions keyed on user Id etc or some other customer claim tagged on the access token - or by using auth0 if for example you tagged the ROLE information as metadata onto the Auth0 User profile. You could then do an Auth0 user profile lookup (management api) by user id and get details that way. See example here for an illustration in Java on getting the userId claim from the JWT access token if you like this approach.
3). Take a look at the Auth0 authorization extension which provides support for user authorization via Groups, Roles, and Permissions. You can define the expected behavior during the login process, and your configuration settings will be captured in a rule that's executed during runtime.
There is no hard and fast answer here, each of the above merits consideration, and what you need for your project. If you really want to leverage the existing declarative authorization as per your code above, then Option 1, and pegging the ROLES information to the scope is the easiest approach.
However, I would actually advocate option 2). above myself, for most "pragmatic" small to medium sized ventures. Here, you would require a little programmatic code inside your Controller endpoint to lookup the ROLES and then make a security decision that way. You could also push out the lookup code into a common Custom Filter that executes before the Controller code is reached, and does the necessary Spring Security manipulation that way - more of an advanced developer option - (I have written libraries in the past that supported this approach for Spring Boot / Security - and can therefore vouch it is a reasonable approach. See here for demonstration but again, sure you would prefer to get on with building your business logic and not detour into building a library, right?).
Option 3). is definitely worth exploring if you are building out a serious enterprise app, and need all the integrations - especially where integration with enterprise connections such as Active Directory are in play.
Leave me comments if you are still confused, but hopefully the above offers sufficient insights to explore further.
Quick update
Further to our discussions, here is a little Rule that gives you the idea you were asking about:
function addRoleScopesToAccessToken(user, context, callback) {
console.log("add-role-scopes-to-access-token rule");
user.app_metadata = user.app_metadata || {};
var roles = user.app_metadata.roles;
if (roles && roles.length > 0) {
context.accessToken.scope = roles.join(' ');
}
callback(null, user, context);
}
And this is how your "app_metadata" might look like:
{
"roles": [
"role1",
"role2"
]
}
You should end up with a JWT access token with the roles added to the scope. eg.

IdentityServer3: Can it be used "side by side" with existing users/authentication?

I'm new to SSO, so hopefully what I'm asking makes sense. So my current setup is a .NET MVC website using OWIN/cookies (app.UseCookieAuthentication()) and a custom user table (not ASP.NET Identity users).
So I'm wondering if I could add IdentityServer3 only for external providers, but leave all my existing user/authentication stuff as is for "local users". So I see that you can implement a custom IUserService to lookup users against your local database, and I think I got that working, but I'd like to even avoid that. And I'd like to avoid themeing the IdentityServer login screen. So something like this:
User hits up page with [Authorize] attribute.
User is redirected to my existing login page (not IdentityServer stuff)
Then my login page would have the external provider button(s) to login with external providers.
Is that possible? Or do you have to run your local users through IdentityServer3 also? I noticed I get an error if you don't provide a IUserService and don't use UseInMemoryUsers() either.
So from following various guides, I have this in my Startup.cs: app.UseIdentityServer(), app.UseCookieAuthentication(), and app.UseOpenIdConnectAuthentication() with Authority set to my IdentityServer endpoint.
Hopefully that made sense, Thanks!
Gonna answer my own question if it helps anyone else. The important piece here is AuthenticationMode in OpenIdConnectAuthenticationOptions. AuthenticationMode.Active is what will redirect the user to your OIDC provider anytime they hit an action with [Authorize].AuthenticationMode.Passive will allow you to use your OIDC provider as an additional authentication method. You want to follow the examples with ExternalLogin() and ExternalLoginCallback() controller actions that issue challenges to the provider and then match the authenticate user with your local user.

Loopback passport login

I want to use Loopback passport to login to my app via a third party. However, rather than having anyone successfully authenticating with the third party, I want to be able to only allow those accounts with an email already configured as a user access (i.e. I want to whitelist people from this provider).
Is this possible? Almost all the examples I have seen with Loopback passport and OAuth and similar strategies more generally seem to assume that I am happy to have every Google / Facebook user access my application, whereas that is not my case.
The loopback-example-passport repository extends a few base models (User, AccessToken, UserIdentity and UserCredential).
You can create a new file /common/models/user-identity.js, which can listen for when new identities are created. In there try something like this:
module.exports = function(userIdentity) {
userIdentity.observe('before save', function(context, next) {
if (context.instance) {
console.log(context.instance.profile._json);
}
}
}
Within context.instance.profile._json, you can observe the details of the newly created user, modify their details or remove it if needed.
I have dived into third-party auth few weeks ago and realized that existing documentation and loopback-example-passport is not enough to read in my case. For example, existing loopback-component-passport is unable to work with custom User models.
I think you can perform operation hook on your UserIdentity model and compare email from UserIdentity.profile.emails array and User model emails with find() and filter.

How to manage API side authorization for Google?

I'm responsible for the API side of our product. We have several different clients, from browsers to iPads to Chromebooks. Right now, all our authentication is done directly from the client to our API, with username & password.
I've inherited some code that does authentication using OAuth, with the usual username/password setup. So inside my OwinAuthConfig class, I have:
var oAuthAuthorizationOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Authenticate"),
Provider = new MyAuthorizationProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
app.UseOAuthAuthorizationServer(oAuthAuthorizationOptions);
Then, through some dark magic, this connects up with my MyAuthorizationProvider class (which inherits OAuthAuthorizationServerProvider), and on login, this invokes the method:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{ ... }
where context contains the important stuff (Username and Password) which I can then use to authenticate the user, build his claims, create an AuthenticationTicket and this information then magically gets returned to the client with the access token etc.
All well and good.
Now I have a new requirement - to allow 3rd party authentication from Google. In this case, the client app (iOS/Android/whatever) does the authentication with Google, and they should just pass the token (and any other required info) to me on the API side. On my side I then need to re-authenticate the Google token, and get all the user info from Google (email, name, etc.), from which I should then again link that to our User table, build up the claims etc. and return a new token to the client, which will be used in all subsequent calls.
Being kinda new to the whole OWIN pipeline thing, I'm not sure exactly how to go about this. I could write a new GoogleAuthController, that just acts like any other controller, and have an API that accepts the Google token, and returns the new token and other info in the same format that the username/password authentication API does it. But 2 things are nagging at me:
I have this awkward feeling like this is the noobie way of doing things, reinventing the wheel, and really there's a super-cool magical way of hooking things together that I should rather be using; and
In MyAuthorizationProvider.GrantResourceOwnerCredentials(), I've got access to an OAuthGrantResourceOwnerCredentialsContext object, which allows me to validate my new AuthenticationTicket. If I'm doing this inside a plain vanilla controller, I have no idea how I would mark that ticket as validated.
Any clues, please?
EDIT I've seen the Google auth flow as described here. I'm still confused by how best to manage the process from the API side. The client will be obtaining the authorization code, and then calling the API with that auth code. I get that then I've got to take that auth code and convert it to a token by calling the Google API. (Or maybe that should be the client's responsibility?) Either way, I then need to use that token to go back to the Google API and get the user's name, email and avatar image, then I need to match up that email with my own database to identify the user and build up their claims. Then I need to return a new token that the client can use to connect to me going forward.
Let me be more specific about my questions, before my question is closed as "too broad":
When the client has completed authentication with the Google API, it gets back a "code". That code still needs to be converted into a token. Whose responsibility should that be - the client or the API? (I'm leaning towards making it the client's responsibility, if just for the reason of distributing the workload better.)
Whether the client is passing through a code or a token, I need to be able to receive it in the API. Should I just use a plain vanilla Controller to receive it, with an endpoint returning an object of type AuthenticationProperties, or is there some special OWIN way of doing this?
If I'm using a plain vanilla Controller, how do I validate my token? In other words, how do I get access to the OWIN context so that I can mark the AuthenticationTicket as validated?
How do I write an automated test that simulates the client side of the process? AFAICT, the authentication wants to have a user physically click on the "Allow" button to grant my app access to their identity stuff, before it will generate the auth code. In an automated test, I would want to pass username/password etc. all from code. How do you do that?
So I found a solution of my own. It's only slightly kludgy, doesn't require referencing any Google OWIN libraries, and best of all, reuses the code from my username/password authentication.
Firstly, I get the app to call the same Authenticate endpoint as I do for username/password, only with dummy credentials, and add in a "GoogleToken" header, containing the token.
In my authentication code, I check for the GoogleToken header, and if it exists, follow that code path to validate on the Google servers, get an email address, and link to my own User table. Then the rest of the process for building claims and returning a new API token follows the original path.
start here : https://developers.google.com/identity/protocols/OAuth2#basicsteps
This explains how oAuth2 works. So you receive a Google token, now you call Google and request the user's details. you will receive their email which is enough to authenticate them. You could store the token as they are valid for a while and you can keep reusing it for whatever you need until it expires or it is invalidated.
Check this discussion on the same subject :
How can I verify a Google authentication API access token?
if you need more info on how OAuth2 works I can point you to one of my own articles : https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
There's a lot to take in, but it sounds like you need to understand how these things work together. Hope this helps.
Update:
I don't have full access to your setup, but I hope that the following code might help you with using Google as ID provider. Please add the following code to your startup.auth.cs file.
var googleAuthOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "ef4ob24ttbgmt2o8eikgg.apps.googleusercontent.com",
ClientSecret = "DAK0qzDasdfasasdfsadwerhNjb-",
Scope = { "openid", "profile", "email" },
Provider = new GoogleOAuth2AuthenticationProvider
{
OnAuthenticated = async ctx =>
{
//You can get the claims like this and add them to authentication
var tokenClaim = new Claim("GoogleAccessToken", ctx.AccessToken);
var emailClaim = new Claim("email", ctx.Email);
var claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(tokenClaim);
claimsIdentity.AddClaim(emailClaim);
HttpContext.Current
.GetOwinContext()
.Authentication
.SignIn(claimsIdentity);
await Task.CompletedTask;
}
},
AuthenticationType = "Google"
};
app.UseGoogleAuthentication(googleAuthOptions);
This allows the Google to act as ID Provider and the OnAuthenticated gets called when the authentication is successful. You can get the claims out of it and use them to signin. Please let me know if this worked, if not give me more details about your setup (what kind of framework, client setup and may be more details about your setup in startup file).
Thank you.
Please see this link for details on how we can use Google as ID Provider. I am sure you might have looked at this link, but in case you missed it. If none of these links work for you please include specific details on where you are deviating from what is mentioned in the links.
I assume you have a different requirement than what is specified in those links. Hence, I will try to answer your questions individually. Please let me know if you have any further questions.
When the client has completed authentication with the Google API, it gets back a "code". That code still needs to be converted into a token. Whose responsibility should that be - the client or the API? (I'm leaning towards making it the client's responsibility, if just for the reason of distributing the workload better.)
Exchanging the code for access token is definitely the responsibility of the API as the token exchange involves sending the ClientId and Client Secret along with the code. Client secret is supposed to be saved on the server side (API) but not on the client
Whether the client is passing through a code or a token, I need to be able to receive it in the API. Should I just use a plain vanilla Controller to receive it, with an endpoint returning an object of type AuthenticationProperties, or is there some special OWIN way of doing this?
This should work seamlessly if you are using the Google provider as mentioned in the above links. If not, the endpoint should be an anonymous endpoint accepting the code and making a request to Google (may be by using HttpClient) to get the access token along with the profile object for user related information.
If I'm using a plain vanilla Controller, how do I validate my token? In other words, how do I get access to the OWIN context so that I can mark the AuthenticationTicket as validated?
You have to implement OnGrantAuthorizationCode as part of your MyAuthorizationProvider class. This gives access to the context to set validated to true.
How do I write an automated test that simulates the client side of the process? AFAICT, the authentication wants to have a user physically click on the "Allow" button to grant my app access to their identity stuff, before it will generate the auth code. In an automated test, I would want to pass username/password etc. all from code. How do you do that?
This can be achieved partially, but, with that partial test you can be sure of good test coverage against your code. So, you have to mock the call to the Google API and assume that you have retrieved a valid response (hard code the response you received from a valid manual test). Now test your code on how it behaves with the valid response. Mock the Google API cal for an invalid response and do the same. This is how we are testing our API now. This assumes that Google API is working fine and tests my code for both valid/ in-valid responses.
Thank you,
Soma.
Having gone through something like this recently, I'll try to answer at least some of your questions:
The client should be getting a token from Google, which you can pass unaltered through to the API:
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var idToken = googleUser.getAuthResponse().id_token;
}
A plain vanilla Controller should do it. The client can subsequently post an object in there, containing at least that token plus the client id (might be useful to know where the request comes from) and even the providerUserId;
Unfortunately I'm not that familiar with the Owin stack
Fully end-to-end integration testing might be tricky, although you might achieve something through tools like Selenium, or some mocking tool. The API however should be testable just by posting some fake data to that vanilla controller, although you might have to rely on some sort of mock implementation when you get to validating that token through Google (although you could also validate it manually on the server, provided you get the Google public api key).

How to grant ACL in Spring Security without an explicit authentication?

When I create a new entity I would like to grant ACL permissions (aka ACL entry) to this new entity. So far so easy :-)
The problem arises in the following scenario:
An end user can create the entity without being authenticated on the web site.
The service that persists this new entity hence runs without an authentication context.
But: to grant ACEs one needs to have an active authentication context.
Spring's JdbcMutableAclService uses SecurityContextHolder.getContext().getAuthentication() to obtain the current authentication, so there seems to be no way to circumvent this requirement.
Any ideas are greatly appreciated!
Found the answer myself:
In a web application there always is an authentication context. If a user is not authenticated the authentication is org.springframework.security.authentication.AnonymousAuthenticationToken which has a single granted authority: ROLE_ANONYMOUS.
Hence it is simple to grant this user the right to create ACLs. Just configure the PermissionGrantingStrategy to use this role to authorize requests.
The main answer does not work in the current version of Spring (5.3.22) and Spring Security (5.7.3). I doubt it even worked back in 2012, when the answer was posted since it does not make sense.
PermissionGrantingStrategy is a class that only contains the method bool isGranted(Acl, List<Permission>, List<Sid>, boolean) which decides if the principals in the List<Sid> can access the object with the corresponding Acl with any of permissions in List<Permission>.
This is the function that is called when a user want to access an object with a certain permission. This method determines if access is granted or denied.
This has nothing to do with allowing anonymous users to modify existing Acls. The actual problem comes from calling MutableAcl aclService.createAcl(ObjectIdentity) when the authentication context is empty. This is implemented by JdbcMutableAclService, provided by Spring. The problem is that MutableAcl JdbcMutableAclService.createAcl(ObjectIdentity) has this call Authentication auth = SecurityContextHolder.getContext().getAuthentication(); which forces the access to authorization context even though the Sid could be passed to the createAcl method, so the business logic would be able to createAcls for the chosen users passed in the arguments.
Instead, we have this call which makes it impossible to use Acls from an unauthenticated context if we want to keep using the Spring Classes.
So, the solution would be reimplement the JdbcMutableAclService so the createAcl method does not call the authentication context, instead it has an extra arguments to indicate the Sid of the user we want to create the Acls.
If anyone has any idea on how to do that it would be greatly appreciated.
I am trying to initialize my Acl tables programmatically when my web app starts, but I cannot do it because my initialization code does not have any authantication.

Resources