How to deploy Databricks cluster with specified permissions? - azure

I am deploying some Databricks clusters using powershell script which takes as an input json file with pre-defined cluster templates, for example:
{
"cluster_name": "test1",
"max_retries": 1,
"spark_version": "5.3.x-scala2.11",
"timeout_seconds": 3600,
"autotermination_minutes": 60,
"node_type_id": "Standard_DS3_v2",
"driver_node_type_id": "Standard_DS3_v2",
"spark_env_vars": {
"PYSPARK_PYTHON": "/databricks/python3/bin/python3"
},
"spark_conf": {
"spark.databricks.delta.preview.enabled": "true"
},
"autoscale": {
"max_workers": 4,
"min_workers": 2
}
}
However, I would like to pre-assign to them some databricks permission groups. Can I do it using such cluster template? I cannot find any property that would allow me to specify those groups.
I can go to one of my clusters that has permissions assigned manually and export it as a json. However, in this case those are also missing from the template.
Thank you in advance!

The workaround that follows is so infinitely hacky, I wouldn't advise anyone to resort to this, if I knew another way. The workaround is to create a web session, log in, get a CSRF token, then issue a POST request to /acl/cluster/<cluster_id> with a map from user_ids to the requested permissions. Here's an example for setting all permissions on a single cluster for a single user (or group) using Python:
import json
import requests
DB_HOST = "db-cluster"
DB_USER = "user"
DB_PASS = "pass"
def change_acl(user_id, cluster_id):
host = DB_HOST
username = DB_USER
password = DB_PASS
session = requests.Session()
login_request = session.post("https://{}/j_security_check".format(host),
data={"j_username": username, "j_password": password})
if login_request.status_code >= 400:
raise Exception("login failed : {}".format(login_request.content))
config_request = session.get("https://{}/config".format(host))
if config_request.status_code >= 400:
raise Exception("config request failed : {}".format(config_request.content))
config = json.loads(config_request.content)
csrf_token = config['csrfToken']
acl_request = session.post(
"https://{}/acl/cluster/{}".format(host, cluster_id),
headers={
"X-CSRF-Token": csrf_token,
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
},
data=json.dumps({
"type": "set",
'permissions': {user_id: ["*"]}
})
)
if acl_request.status_code >= 400:
raise Exception("acl request failed : {}".format(acl_request.content))
If you find a better way, please let me know. The worst thing about this is you have to log in with username and password instead of a bearer token. The second worst thing is that this may break without any notice.
I hope the developers will find the time to implement this functionality in the near future.

Note: You cannot specify the permissions while creating a cluster using Clusters API . You should use "Group API" or "Admin Console"
Request structure of create cluster shown as follows:
Privileges can be granted to users or groups that are created via the groups API and Admin Console. Each user is uniquely identified by their username (which typically maps to their email address) in Databricks. Users who are workspace administrators in Databricks belong to a special admin role and can also access objects that they haven’t been given explicit access to.
Hope this helps.
If this answers your query, do click “Mark as Answer” and "Up-Vote" for the same. And, if you have any further query do let us know.

Related

How to manage Azure DevOps group permissions using Rest API

I'm working on an automation task where I need a group to have a set of permissions on Repos, Pipelines, and releases, etc. I'm looking for a Rest API that can manage the permissions for this group.
For Example:
At Cross repo policies, how do I manage/set the permissions for the group "PROJECT ADMINISTRATORS" to allow the "Bypass policies when pushing", "Bypass policies when pushing", etc using a Rest API.
Thank you in Advance.
Based on your requirement, you could use the Rest API: Access Control Entries - Set Access Control Entries
POST https://dev.azure.com/{organization}/_apis/accesscontrolentries/{securityNamespaceId}?api-version=6.0
Request Body:
{
"token": "repoV2/{ProjectID}/{RepoID(If you want to set the permission for a single repo)}",
"merge": true,
"accessControlEntries": [
{
"descriptor": "Microsoft.TeamFoundation.Identity;S-....",
"allow": 32768,
"deny": 0,
"extendedinfo": {}
}
]
}
You can get the parameter values needed in the Rest API through the following methods:
securityNamespaceId:
GET https://dev.azure.com/{OrganizationName}/_apis/securitynamespaces?api-version=6.0
In the Response Body: you could search for the Git Repositories.
Then you could get the namespaceid and Parameter values corresponding to permissions.
For example:
To get the Group Identity(S-...), there is no directly Rest API to get it. You use the following method to get it:
1.Get the descriptor:
GET https://vssps.dev.azure.com/{org name}/_apis/graph/users?api-version=5.1-preview.1
2.Using the following C# code to convert it:
public static string Base64Decode(string base64EncodedData)
{
var lengthMod4 = base64EncodedData.Length % 4;
if (lengthMod4 != 0)
{
//fix Invalid length for a Base-64 char array or string
base64EncodedData += new string('=', 4 - lengthMod4);
}
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
Here has a blog which written by our Azure Identity Team engineer, you could refer to it for more detailed information.
In addition, you can also obtain the values of all parameters directly through the browser F12 record.

How to query the "Exposed Api" for all users calendars in a Tenant?

I want to be able to - from a crohn job on a 3rd. party server - query and modify all users in my the Tenants (organisation) calendars - but i just end up with a "Application ID URI" that i don't know what to do with.
No matter how i query the microsoft graph API i get "Invalid Audience" and the docs on the subject doesn't really seem to highlight how exactly to specify the correct "audience" or what a "resource" actually entails.
These are the steps i have taken in the Azure Active Directory portal:
I use the Client Credentials Grant flow so i can access with a Cron and not through a user. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
1) Registered an application in the portal. So i get some ID's (anonymized here)
Application (client) ID
:
51ed7b6d-d33e-491e
Directory (tenant) ID
:
c181f4f3-912b-4acf-
Object ID
:
3f52a799-f2ab-4161-a81c
2) Created a secret so i can provide that together with the Application id to get a token.
3) Given "Api Application Permissions" to https://graph.microsoft.com/Calendars.ReadWrite.
4) "Exposed an Api" and called it's scope "readwrite calendars" so the Application ID URI with the scope end up being: api://51ed7b6d-d33e-491e-9d40-1/readwritecalendars
5) Authorized the API to the application with the Application (client) ID from step 1 so i don't need admin consent to query.
Problem is now i just end up with an "Application ID URI", okay how i do i exactly query my for the calendars then?
I am using https://github.com/TheNetworg/oauth2-azure here:
I am able to successfully get a token:
$provider = new \TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
'redirectUri' => 'http://www.google.dk'
]);
$provider->tenant = 'secret';
$token = $provider->getAccessToken('client_credentials', [
'resource' => 'https://graph.windows.net',
]);
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
return $token ;
Gives me:
{
"token_type": "Bearer",
"ext_expires_in": "3600",
"expires_on": "1562669834",
"not_before": "1562665934",
"resource": "https://graph.windows.net/",
"access_token": "longstringofnumbers",
"expires": 1562269224
}
There is no "Aud" or "Audience" field returned.
This i where i get confused, how exactly do i form a link, how do i say that i want to query all calendars with the token?
Looking at the outlook graph documentation it specifies i need to query like this (https://learn.microsoft.com/en-us/graph/api/user-list-calendars?view=graph-rest-1.0&tabs=http):
GET /me/calendars
This doesn't really make sense to me as "me" seems to imply a user, i am trying to query stuff in a tenant not tied to a specific user?
Anyway if i try to query like:
$provider->get('me/calendars',$token);
Or different combinations of this i just get:
Access token validation failure. Invalid audience.
To sum it all up: how do i actually query the API to list/modify calendars, what is the actual endpoint i have to hit? And where do i put the actual query?
Thanks in advance!
A result would be a JSON object instead of the error message. A successful return to the query. In this case a list of all users calendars, or a "successfully updated" after modifying a calendar.
In Azure AD you can specify "API Permissions" for an app registration. If you want to query all calendars with one access token you should use "Application permissions".
Point 4 is for other types of applications like Office Add-Ins.
For all request you can use the default Graph endpoint https://graph.microsoft.com/v1.0/. So if you wan't to query a user calendar you should use this:
GET https://graph.microsoft.com/v1.0/<UserId or UPN>/calendar
Got it working with:
$provider = new \TheNetworg\OAuth2\Client\Provider\Azure([
'clientId' => env('OAUTH_APP_ID'),
'clientSecret' => env('OAUTH_APP_PASSWORD'),
]);
$provider->tenant = env('AZURE_TENANT');
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
$token = $provider->getAccessToken('client_credentials', [
'resource' => 'https://graph.microsoft.com',
]);
$currentCalendarEvents = $provider->get('users/some#some.com/calendars/Calendar/events?$top=1000', $token);
The $provider->resource and urlapi has to be set before the request off course as written in the docs: https://github.com/TheNetworg/oauth2-azure#microsoft-graph

What is the best way to implement roles and permission in Express REST Api

I need kind of expert opinion to implement Roles and Permission in Express js. I'm planning to develop Restful Api using Express js but didn't get sufficient information to implement Roles and Permission although there are tons of option are available for authentication and authorization.
Create Tables
First you need to create your tables that will hold the associations between roles, permissions, and resources:
Create a roles table ('Admin', 'User', 'Guest')
Create a resources table ('Users', 'Projects', 'Programs')
Create a permissions table ('Create', 'Read','Write','Delete','Deny')
Create a junction table with all three tables as sources
You may not need that kind of granularity for the permissions table, but some people like it. For example, you don't really need 'Deny', since you just check for Read != true.
Now when you want the permissions of a role on a resource, you just look up role_id and resource_id and check for which permissions are set to true.
Create Middleware
Since you're using express, middleware will be easy to add. For example, let's say you have a router called users:
users.post('/', getAuth, handleUserPost)
Assuming you have a token of some sort on the request that identifies the user making the post, and attaching the user instance to the request object you can do this:
getAuth = function (req, res, next) {
if(req.user) {
db.getPerms({role_id: req.user.role_id, resource_id: req.resource.id})
.then(function(perms){
var allow = false;
//you can do this mapping of methods to permissions before the db call and just get the specific permission you want.
perms.forEach(function(perm){
if (req.method == "POST" && perms.create) allow = true;
else if (req.method == "GET" && perms.read) allow = true;
else if (req.method == "PUT" && perms.write) allow = true;
else if (req.method == "DELETE" && perm.delete) allow = true;
})
if (allow) next();
else res.status(403).send({error: 'access denied'});
})//handle your reject and catch here
} else res.status(400).send({error: 'invalid token'})
}
That code was roughed in just for this example, so I wouldn't go copy and pasting it, but it should give you the right idea.
Role rights in Node.js
Part 1:What is role and rights?
Role rights implementation is important part of any software.Role is a position of responsibility and every responsibility enjoys some rights given to them.There may be some common rights between few roles and some rights may strictly belong to specific role.
Rights are Urls that a role is authorised to access.It is thus necessary to create collection in db storing information of rights to a role.
We have role collection schema as
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const RoleSchema = new Schema({
roleId:{
type:String,
unique:true,
required:[true,"Role Id required"]
},
type:{
type:String,
unique:true,
required:[true,"Role type is required"]
},
rights:[{
name: String,
path: String,
url: String
}]
});
module.exports = Role = mongoose.model('role',RoleSchema);
Now remember every role that is supose to exist is in Role collection and of above schema type.
In schema rights array of object we see the object has keys:
name(for name of url like "set-username")
path(for base path hit "/users/")
url(requested url or complete path "/users/set-username")
Thus if a user with role user has right to change username then he can hit url
/users/set-username.However a wanderer will not be able to access this url.A higher role like admin & superadmin should logically have access to all lower role rights(urls).
Role in real application are:-
Wanderer (Someone who is just visiting our site.He should be able to access all public routes.Simple Urls/Public urls accessible to all thus need not to make a seprate role for this as it is not any authenticated right.)
Guest (Someone who has registered but not verified say email not verified).
User (Someone who has his verified email)
Admin (Made a Admin by SuperAdmin after verifying.he enjoy most of rights)
Superadmin (Master of application.He enjoy some more sophisticated rights.More rights then admin)
Till Now we have understood what excatly is right and how it is mapped to a role.
Part 1.5:Registerd Urls/Config Urls
Here we have a file called registeredUrls.js which is like:
module.exports = {
simple:{
"/":[""],
'/users/':["login","register"],
},
auth:{
//admin
'/admin/': ['load-users' , 'set-new-password','delete-user'],
'/teacher/':["add-teacher","delete-teacher","edit-teacher"],
'/student/':["add-student","delete-student","edit-student","test-result"],
//user
'/test/':["view-test","submit-test"],
'/profile/': ['change-username', 'update-profile-data', 'set-new-password', 'upload-pic', 'update-social-links'],
'/teacher/':['load-teacher'],
'/student/':['load-student']
}
}
Similarly confgUrls.js
const configUrls= {
'/roles/': ['get-rights', 'create', 'update-rights', 'load', 'delete', 'assign']
}
module.exports = configUrls;
Part 2:Creating SuperAdmin
This is most essential part of application.Whenever server starts for first time or restart/reboot this step occurs.In config/init.js follow procedure:
Load All simple urls(public) and Auth Urls(admin & users) & super-admin-specific urls into superAdminRights[].
Then run a function to create a user with role superadmin if doesn't exist.
Get a Role of type:"superadmin" if found:replace its rights with new rights(superAdminRights).else:create Role of type :"superadmin" and then fill its rights(superAdminRights).
At end of this function call we are always sure that we have a superadmin in application with all its sophisticated urls/rights initialised.
Part 3:Super-Admin-Specific-Urls
These are rights that are enjoyed by super admin only and must be maintained in seprate file in parallel to registerd url file.These include url rights which map routes used only by superadmin.
Here we have routes to create role,load roles,get-rights for a roleId,update-rights for roleId/role type, assign-role to a user,delete a role.
For each user in code we need to change their role from guest to user(say after email verification).Or guest/user to admin by superadmin using assign-role url.Then updating admin rights using route update-rights.
The process ensure that every role has A collection Document and filled rights there.
Part 4:Authenticator Middleware
This heart of our RBACS logic.Here we use a middleware which follow process:
1. Fill all authentication required urls in a [AUTH_URLS] with auth-urls(registeredUrls.js) & super-admin-specific-urls(confgUrls.js) and simple url in different [SIMPLE_URLS].
2. Then check if (AUTH_URLS.indexOf(request.url) > -1){3rd step} else if (SIMPLE_URLS.indexOf(request.url)>-1){then it is public url so simple allow next()} else { response unknown url}
3. In this step we know that url being requested in AUTH_URLS thus required token check for authorization token header if found then extract token from it then{4th step}.if no authorization header found response "required token"/"unknown".
4. Token found, now verify that this token has a valid session.If yes {5th step} else token session not found login again.
5. validate jwt token verifying it if verified{6.step} else response "not valid jwt token".
6.till now correct url requested & token session exist & jwt valid token.Now using role-type information from session(stored in session is basic info of user and token) find in Role for this user session role-type thus we have its rights[].Now see if the request.url is included in rights[].if found {7th step} else {reponse "role not found/unknown user"}.
7. if found then {has access to this url next() } else { response "access denided"}

OneDrive for Business API issues on Discovery and Authorization

I've been trying to implement OneDrive Business API according to this OneDrive Release Notes. We've already implemented OneDrive end users API without any issue.
First obvious thing to do is to handle OAuth2 authentication to get right tokens, first to discover {tenant}-my.sharepoint.com specific Tenant OneDrive Business URI and after that get tokens for that tenant. Documenation for that purpose could be found here.
Following that tutorial we have been able to do the following:
Register the App in Azure AD. Done
Sign into OneDrive for Business
Log in and get an authorization code. Done
Redeem the authorization code for tokens. Done
Discover the OneDrive for Business resource URI. FAIL
Redeem refresh token for an access token to call OneDrive API. Done
Make a request to the OneDrive API. FAIL
It can be appreciated, we had issues on step 2, Discover the OneDrive for Business resource URI and Make a request to the OneDrive API.
Issue on Discover the OneDrive for Business resource URI
The problem with this part of the process is, although we are hitting to api.office.com/discovery/v2.0/me/services with the first Access Token obtained after redeem with resource api.office.com/discovery/, we are not getting in the list of services tenant specific sharepoint URI for OneDrive for Business. Any entry in the list we are getting come with capability = "MyFiles" AND serviceApiVersion = "v2.0" according documentation. In fact any entry in the list has the structure {tenant}-my.sharepoint.com in serviceEndpointUri. This is JSON response i am getting back. I removed some of the sensitive data:
{
"#odata.context" : "https://api.office.com/discovery/v2.0/me/$metadata#allServices",
"value" : [ {
"capability" : "Directory",
"providerName" : "Microsoft",
"serviceAccountType" : 2,
"serviceApiVersion" : "",
"serviceEndpointUri" : "http://azure.microsoft.com/",
"serviceName" : "Microsoft Azure",
"serviceResourceId" : null
}, {
"capability" : "MyFiles",
"providerName" : "Microsoft",
"serviceAccountType" : 2,
"serviceApiVersion" : "",
"serviceEndpointUri" : "http://www.microsoft.com/en-us/office365/online-software.aspx",
"serviceName" : "Office 365 SharePoint",
"serviceResourceId" : null
}, {
"capability" : "RootSite",
"providerName" : "Microsoft",
"serviceAccountType" : 2,
"serviceApiVersion" : "",
"serviceEndpointUri" : "http://www.microsoft.com/en-us/office365/online-software.aspx",
"serviceId" : "O365_SHAREPOINT",
"serviceName" : "Office 365 SharePoint",
"serviceResourceId" : null
}, {
"capability" : "MyFiles",
"providerName" : "Microsoft",
"serviceAccountType" : 1,
"serviceApiVersion" : "",
"serviceEndpointUri" : "https://g.live.com/8seskydrive/HomePageUrl",
"serviceName" : "OneDrive",
"serviceResourceId" : null
} ]
}
The problem with this is if i logged in to my portal.office.com and check my sharepoint urls, it is well configured and i can see {tenant}-my.sharepoint.com URI.
Issue on Make a request to the OneDrive API
Apart i am not able to discovery correct tenant sharepoint URI, if i hardcode the URL to redeem next Access Token request with my tenant sharepoint URI, I am getting an access token but when i want to make a call for example to https://{tenant}-my.sharepoint.com/drive/root or any other endpoint i am getting 401 Unauthorize response in every call, even when the token has just been acquired. Here is a handshake example. I am hiding sensitive data:
curl -v 'https://{tenant}-my.sharepoint.com/drives' -H 'Authorization: Bearer TOKEN_ACQUIRED'
Connected to {tenant}-my.sharepoint.com port 443
GET /drives HTTP/1.1
Host: {tenant}-my.sharepoint.com
Authorization: Bearer TOKEN_ACQUIRED
HTTP/1.1 401 Unauthorized
Could you advice me with this? Is there some configuration missing in my tenant? Is there some configuration missing in my Azure AD App?
BTW, permissions scope on my App i am getting in every redeem are AllSites.FullControl AllSites.Manage MyFiles.Write Sites.Search.All TermStore.ReadWrite.All User.Read.All. I think i have permissions properly set.
Best,
List item
Might be a bit late, but this blog article addresses how to use the OneDrive API and OneDrive for Business API exactly the same.
Here is a quick Java code snippet:
CloudRail.setAppKey("[CloudRail License Key]");
// CloudStorage cs = new OneDrive(redirectReceiver, "[clientIdentifier]", "[clientSecret]", "[redirectUri]", "[state]");
CloudStorage cs = new OneDriveBusiness(redirectReceiver, "[clientID]", "[clientSecret]", "[redirectUri]", "[state]");
new Thread() {
#Override
public void run() {
cs.createFolder("/TestFolder");
InputStream stream = null;
try {
stream = getClass().getResourceAsStream("Data.csv");
long size = new File(getClass().getResource("Data.csv").toURI()).length();
cs.upload("/TestFolder/Data.csv", stream, size, false);
} catch (Exception e) {
// TODO: handle error
} finally {
// TODO: close stream
}
}
}.start();

eve U.R.R.A. doesn't work with HMAC

run.py:
class HMACAuth(HMACAuth):
def check_auth(self, userid, hmac_hash, headers, data, allowed_roles, resource, method):
accounts = app.data.driver.db['accounts']
user = accounts.find_one({'username': userid})
if user and '_id' in user:
secret_key = user['secret_key']
self.set_request_auth_value(user['_id'])
# in this implementation we only hash request data, ignoring the headers.
hm = hmac.new(bytes(secret_key, encoding='utf-8'), data, sha1).digest()
return user and base64.b64encode(hm).decode() == hmac_hash
settings.py:
vms = {
'additional_lookup': {
'url': 'regex("[\w]+")',
'field': 'name',
},
'cache_control': '',
'cache_expires': 0,
'public_methods': [],
'public_item_methods': [],
'resource_methods': ['GET', 'POST'],
'item_methods': ['GET','PATCH','DELETE'],
'auth_field': 'user_id',
'schema': vm_schema,
}
my problem is that every user is receiving all the VMs info when he/she send a GET request to localhost:5000/vms.
With the TokenAuth authentication this didn't happen.What am I missing??
PS: Eve 0.5-dev on Python 3.3.5
Since everything was working fine with token based authentication, and since there's nothing really different between the two methods expect the custom class itself, I would investigate around its behavior.
I would start by checking if documents are actually being stored with the proper user_id value, maybe by using the mongo shell. If not, make sure that the documents that you are inspecting have been saved with your custom HMAC class active. Add a breakpoint and track your code, simple stuff like that. Hope this helps

Resources