1
1
# TODO: test
2
2
import logging
3
3
from typing import Optional , Tuple
4
+ from enum import Enum
4
5
5
6
import yaml
6
7
8
+
9
+ class AuthType (Enum ):
10
+ CREDENTIALS = 1
11
+ LOGIN_PASSWORD = 2
12
+
13
+
7
14
from redash .query_runner import (
8
15
TYPE_BOOLEAN ,
9
16
TYPE_DATETIME ,
@@ -68,9 +75,12 @@ class PowerBIDAX(BaseHTTPQueryRunner):
68
75
requires_url = False
69
76
url_title = "Power BI URL"
70
77
username_title = "Username"
71
- password_title = "Password"
78
+ password_title = "Password/Token "
72
79
default_url = "https://api.powerbi.com/v1.0/myorg"
73
80
default_scopes = '["https://analysis.windows.net/powerbi/api/.default"]'
81
+ default_authority_url = (
82
+ "https://login.microsoftonline.com/<tenant name/yourdomain.com>"
83
+ )
74
84
75
85
@classmethod
76
86
def configuration_schema (cls ):
@@ -83,7 +93,7 @@ def configuration_schema(cls):
83
93
"authority_url" : {
84
94
"type" : "string" ,
85
95
"title" : cls .authority_url_title ,
86
- "default" : "https://login.microsoftonline.com/<tenant name/yourdomain.com>" ,
96
+ "default" : cls . default_authority_url ,
87
97
},
88
98
"scopes" : {
89
99
"type" : "string" ,
@@ -96,6 +106,7 @@ def configuration_schema(cls):
96
106
"client_id" ,
97
107
"authority_url" ,
98
108
]
109
+ schema ["required" ].remove ("username" )
99
110
return schema
100
111
101
112
@classmethod
@@ -112,7 +123,6 @@ def __init__(self, *args, **kwargs):
112
123
self .configuration ["url" ] = self .configuration .get ("url" , self .default_url )
113
124
scopes = self .configuration .get ("scopes" , self .default_scopes )
114
125
self .configuration ["scopes" ] = scopes
115
- self .configuration ["scopes_array" ] = json_loads (scopes )
116
126
117
127
def test_connection (self ):
118
128
_ , error = self .get_response ("/availableFeatures" )
@@ -122,18 +132,49 @@ def test_connection(self):
122
132
def get_auth (self ):
123
133
return None
124
134
135
+ def get_credentials (self ):
136
+ username = self .configuration .get ("username" )
137
+ password = self .configuration .get ("password" )
138
+ if password :
139
+ return (username , password )
140
+ if self .requires_authentication :
141
+ raise ValueError ("Username and Password or Token required" )
142
+ else :
143
+ return None
144
+
125
145
def get_authorization (self ):
126
146
client_id = self .configuration ["client_id" ]
127
147
authority_url = self .configuration ["authority_url" ]
148
+ self .configuration ["scopes_array" ] = json_loads (self .configuration ["scopes" ])
128
149
scopes = self .configuration ["scopes_array" ]
129
- username , password = super ().get_auth ()
130
- app = msal .PublicClientApplication (client_id = client_id , authority = authority_url )
131
- result = app .acquire_token_by_username_password (
132
- username = username ,
133
- password = password ,
134
- scopes = scopes ,
135
- )
150
+ username , password = self .get_credentials ()
151
+ if self .configuration .get ("username" ) is None :
152
+ self .auth_type = AuthType .CREDENTIALS
153
+ else :
154
+ self .auth_type = AuthType .LOGIN_PASSWORD
155
+ if self .auth_type == AuthType .CREDENTIALS :
156
+ app = msal .ConfidentialClientApplication (
157
+ authority = authority_url ,
158
+ client_id = client_id ,
159
+ client_credential = password ,
160
+ )
161
+ result = app .acquire_token_for_client (
162
+ scopes = scopes ,
163
+ )
164
+ elif self .auth_type == AuthType .LOGIN_PASSWORD :
165
+ app = msal .PublicClientApplication (
166
+ authority = authority_url ,
167
+ client_id = client_id ,
168
+ )
169
+ result = app .acquire_token_by_username_password (
170
+ username = username ,
171
+ password = password ,
172
+ scopes = scopes ,
173
+ )
174
+ if "error" in result :
175
+ raise ValueError (f"Couldn't acquire token: { result } " )
136
176
access_token = result ["access_token" ]
177
+ logger .debug (result )
137
178
return f"Bearer { access_token } "
138
179
139
180
def get_response (self , url : str , auth = None , http_method = "get" , ** kwargs ):
0 commit comments