I want to use Azure Active Directory to allow users to read and write to Azure storage (specifically all Blobs and Tables) from a single-page web app.
I started like this:
import { InteractiveBrowserCredential } from '#azure/identity';
import { TableClient, TableServiceClient } from '#azure/data-tables';
const credentials = new InteractiveBrowserCredential({
clientId: myAuthConfig.clientId,
tenantId: myAuthConfig.tenantId,
});
const client = new TableServiceClient(
`https://${myAuthConfig.storageAccountName}.table.core.windows.net`,
credentials
);
client.listTables().byPage().next().then(console.log);
This works totally fine! I can see all the tables on the account. But then I wanted to list some of the data in on of the tables. So I did:
const client = new TableClient(
`https://${myAuthConfig.storageAccountName}.table.core.windows.net`,
'<table name>',
credentials
);
client.listEntities().byPage().next().then(console.log);
But this gives an error:
{
"odata.error": {
"code":"AuthorizationPermissionMismatch",
"message": {
"lang":"en-US",
"value":"This request is not authorized to perform this operation using this permission.\nRequestId:<uuid>\nTime:2021-10-28T18:04:00.0737419Z"
}
}
}
I'm very confused by this error. As far as I can tell I've done everything right. I followed every tutorial. I've set up active directory permissions for my app to use the storage API, my Microsoft account has permission to access the tables, OCRS is enabled, etc.
I'm not sure why I would have access to see a table but not see what's in it. I tried to use InteractiveBrowserCredential.authenticate to explicitly set scopes like this:
const scopes = ["User.Read"]
credentials.authenticate(scopes).then(console.log);
It works fine for User.Read but I couldn't figure out what scopes corresponded to Storage read/write access. If I added a scopy like "Microsoft.Storage" it told me that it didn't exist
Has anyone got an error like this before? What am I supposed to do here?
Thank you #gaurav mantri ,Posting your suggestion in comment as an answer.
From error it looks like your service principal does not have access permission to your table storage data. You should either grant permission using a RBAC role on the storage account resource (add to storage account contributors or readers) as below. Or use Storage Explorer to grant permission.
In your storage account please check, if you have Storage Table Data Contributer /Storage table data reader roles assigned as commented by #gaurav mantri
If not , you can add them
go into your storage account > IAM > Add role assignment, and add the special permissions
If roles are already assigned , the issue might be due to storage account being protected by firewall. Please try configure in Firewall and virtual networks of your storage account to add an existing virtual network or create a new vnet.If there is no issue you may allow access from all networks.
References:
Authorize access to tables using Active Directory - Azure Storage |
Microsoft Docs
Assign an Azure role for access to table data using powershell -
Azure Storage | Microsoft Docs
Related
I am making a voice recording application in which the recording is saved in firebase storage in a folder named emailID (user email id when registered). I want that only the user can have access to that folder. Means that user can only open their own folder (matching name to their email). I want this feature to make my application more secure. I need the javascript code for the storage rules (according to my need) in firebase.
In this way, no one can get access to firebase storage until they log in, and after that, they can have access to their folder only.
It sounds like you're looking for this:
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "Zrecorder/<email>/path/to/file.txt"
match /Zrecorder/{email}/{allPaths=**} {
allow read, write: if request.auth.token.email == email;
}
}
}
Also see:
The Firebase documentation on properties in the request variable
For a work-related app I use Firebase authentication with Microsoft. In this case, however, it is important that only people from my company (we use Office 365) can sign into this application. I have everything set-up and working in a non-firebase context. But when I use Firebase for authentication, it seems to always point to the /common/ endpoint. This causes problem with my single-tenant-application. If I set the application to accept all tenants, the app works again. But obviously, now everyone can log into my application.
The pop-up is called with a rather conventional:
const provider = new auth.OAuthProvider("microsoft.com");
provider.setCustomParameters({
tenant: "[tenantName].com"
});
auth()
.signInWithPopup(provider)
.then(result => {
But I can't find any instructions on changing the oauth endpoint to use the single tenant endpoint.
How would I go about doing this?
But I can't find any instructions on changing the oauth endpoint to
use the single tenant endpoint.
We can not change the oauth endpoint, even though we add the tenant information to customParameters. The endpoint always use common as the value of tenant. This is the default design.
If we enable Microsoft as a sign-in provider, users using Microsoft accounts (Azure Active Directory and personal Microsoft accounts) can sign in.
Turns out the above is not exactly true. I've switched to signing in with a redirect, and now it (mysteriously) works.
const provider = new auth.OAuthProvider("microsoft.com");
provider.setCustomParameters({
tenant: "[tenant].com"
});
auth().signInWithRedirect(provider);
I have tested this. The tenant is named in the redirect, and people from other tenants cannot log in.
My code (Node.js):
const GraphkManagementClient = require('azure-graph');
client = new GraphkManagementClient(credentials, tenantId);
client.users.get(principalID);
The last line throws:
Authorization_RequestDenied: Insufficient privileges to complete the
operation.
I know how to grant privileges on Azure portal, but I don't know which one is the correct privilege of azure-graph for performing this operation. The list is so long:
(And this is just the beginning of the list)
Firstly you are assigning permissions for the wrong API as per screenshot in your question. It shows "Microsoft Graph" although your code will be using Azure AD Graph API.
In Azure portal navigate to Azure Active Directory > App registrations > Your app > Required permissions > Add (now in the Select an API select "Windows Azure Active Directory")
Now, if credentials used in your code are client id/app id and app secret, then you need to assign "Read directory data" under Application Permissions. For code like msRestAzure.loginWithServicePrincipalSecret
Otherwise, if you are prompting users to enter their credentials and doing something like interactive login, then assign "Read directory data" under Delegated Permissions. For code like msRestAzure.interactiveLogin()
Once you assign the relevant permissions, if any of those requires Admin consent, like it does in the above two cases I have shown, do the Admin consent. You can do it conveniently for the same tenant using "Grant Permissions" button at the end of the process.
Under your Microsoft Graph permissions for the App Registration in Azure Active Directory, grant 'Read Directory Data' permissions. This should be sufficient to make that call work. If that is too elevated, reference this for more information:
Microsoft Graph Permissions Reference
I’m trying out the Authentication component in Firebase.
A) I have a situation where the web client javascript code firebase-app.js and firebase-auth.js 3.3.0...
firebase.auth().onAuthStateChanged and
firebase.auth().currentUser
... return different expected logged in user values, than the jvm
client [com.firebase/firebase-client-jvm "2.5.2"]. The JVM client
returns null user data.
My JVM client code is taken from Firebase’s QuickStart Guide. In
the JVM client, neither onAuthStateChanged handler is called, nor
does firebaseObj.getAuth() return any data.
I’m wondering where the discrepancy is. The web client was initialized
with “codepairio.firebaseapp.com”.
var config = { ... authDomain: “<my-firebase-app>.firebaseapp.com"
};
firebase.initializeApp(config);
B) The java client was initialized with “https://.firebaseio.com”. I’m using this URL as it’s specified in the guide and mentioned here. Also, if you try
to use “.firebaseapp.com”, you’ll get an error:
“IllegalStateException For a custom firebase host you must first set your authentication server before using authentication features!”.
So with that out of the way, we have...
new Firebase("https://<my-firebase-app>.firebaseio.com”);
Any ideas on how to get them to observe the same source of truth?
====> [EDIT]
Ok, I've gotten a bit further. It turns out that I was using an older firebase API (A) than the latest (B).
A) https://www.firebase.com/docs/android/guide/user-auth.html
B) https://firebase.google.com/docs/auth/server/
So if we look at Firebase's documentation for how to handle user's, we see this:
A Firebase User object represents the account of a user who has signed
up to an app in your Firebase project. Apps usually have many
registered users, and every app in a Firebase project shares a user
database.
A Firebase User instance is independent from a Firebase Auth instance. This means that you can have several references to different
users within the same context and still call any of their methods.
But i) the notion of FirebaseAuth.getInstance().getCurrentUser() doesn't make sense if our app is dealing with multiple users. And further, the FirebaseAuth.getInstance().getCurrentUser() method doesn't even exist. The FirebaseAuth class file (in com.firebase/firebase-client-jvm "2.5.2"), doesn't reflect the documentation.
$ javap -classpath ~/.m2/repository/com/google/firebase/firebase-server-sdk/3.0.1/firebase-server-sdk-3.0.1.jar com.google.firebase.auth.FirebaseAuth
Compiled from "FirebaseAuth.java"
public class com.google.firebase.auth.FirebaseAuth {
public static com.google.firebase.auth.FirebaseAuth getInstance();
public static synchronized com.google.firebase.auth.FirebaseAuth getInstance(com.google.firebase.FirebaseApp);
public java.lang.String createCustomToken(java.lang.String);
public java.lang.String createCustomToken(java.lang.String, java.util.Map<java.lang.String, java.lang.Object>);
public com.google.firebase.tasks.Task<com.google.firebase.auth.FirebaseToken> verifyIdToken(java.lang.String);
static com.google.api.client.json.JsonFactory access$000();
static com.google.firebase.auth.internal.FirebaseTokenVerifier access$100(com.google.firebase.auth.FirebaseAuth);
static {};
}
C) So far, using Firebase's Authentication service, on the server is very opaque to me at the moment. Can someone clarify the semantics of handling multiple users, getting lists of logged in users, verifying users with request tokens, etc. Where's the working API for all this?
I actually got an answer back, from Firebase Support, on this. Turns out that, based on the documentation, the capabilities available for the server side (nodejs and java) in terms of authentication are only i) creating custom tokens and ii) verifying ID tokens. As of now, handling users or getting the current user is not supported yet.
For the creation and verifying tokens in the server side, you can refer to this guide for more information. You can also check these posts for more information.
Firebase Java client with custom authentication
Is it still possible to do server side verification of tokens in Firebase 3?
https://firebase.googleblog.com/2013/03/where-does-firebase-fit-in-your-app.html
Hth
This is driving me totally crazy. I've set up an FB app and retrieved an access token by visiting: https://graph.facebook.com/oauth/access_token?grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET.
Now I want to grab a (publicly available) feed from this URL: https://graph.facebook.com/PAGE_OR_USER_ID/feed?access_token=ACCESS_TOKEN
It works fine when I try it with my own user ID or even when I try another random page but it DOESN'T work when I enter the PAGE_ID I need it to work with.
Here are some examples:
This works fine (a friend of mine's Facebook page):
https://graph.facebook.com/tatchit/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
This also works fine (my own Facebook ID):
https://graph.facebook.com/al.dev.7/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
This doesn't work (the client's Facebook page):
https://graph.facebook.com/142616539131188/feed?access_token=213451182120494|JgAwuCE74lh51t1pKMuRM2mz3GU&limit=10&offset=0
I don't get any errors but the result is empty.
If I try the Graph API Explorer it also works fine:
https://developers.facebook.com/tools/explorer/?method=GET&path=142616539131188%2Ffeed
But not if I enter my own access token. From what I understand the access tokens you get in the API Explorer are temporary so I don't want to use that.
How can this be?
Also. I've struggled to understand this whole access-token, client-id, app-id-business for ages now - is there a good tutorial where all this stuff is explained? I've never had this work without problems ever.
Thank you
You should be using user access token for all the above queries. App Access token is used when you want to do something like check the app insights so and so.
When the pages has age restrictions or something so, app token wont be able to get through, but since the user is already a member of the page, you can use the user access token to get the data.
Add : Quoting from the documentation,
Note that the **app access token** is for publishing purposes permitted by the publish_actions and publish_stream permissions. You will be **unable to retrieve information** about the status update post with the given ID using the app access token. Instead, you should use a **user access token** for such purposes.
Other Capabilities of an App Access Token
There is a limited set of information that can be retrieved from Facebook using an App Access Token.
Basic Profile Info of a User (ID, Name, Username, Gender)
A User’s Friends and their IDs
Permissions granted by the User to your App
Read : https://developers.facebook.com/docs/opengraph/using-app-tokens/
So you should be querying with the user_access token to access all the informations that you are looking for, not with an app access_token.
You are using an App Access token instead of a User Access token. Some of the pages you are viewing may have a country or age restriction set, so using an app token will not work.
See: http://developers.facebook.com/docs/concepts/login/access-tokens-and-types/