1# NOTE: This module will go out of support by March 31, 2023. For authenticating with Azure AD, use module [azidentity](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity) instead. For help migrating from `adal` to `azidentiy` please consult the [migration guide](https://aka.ms/azsdk/go/identity/migration). General information about the retirement of this and other legacy modules can be found [here](https://azure.microsoft.com/updates/support-for-azure-sdk-libraries-that-do-not-conform-to-our-current-azure-sdk-guidelines-will-be-retired-as-of-31-march-2023/).
2
3# Azure Active Directory authentication for Go
4
5This is a standalone package for authenticating with Azure Active
6Directory from other Go libraries and applications, in particular the [Azure SDK
7for Go](https://github.com/Azure/azure-sdk-for-go).
8
9Note: Despite the package's name it is not related to other "ADAL" libraries
10maintained in the [github.com/AzureAD](https://github.com/AzureAD) org. Issues
11should be opened in [this repo's](https://github.com/Azure/go-autorest/issues)
12or [the SDK's](https://github.com/Azure/azure-sdk-for-go/issues) issue
13trackers.
14
15## Install
16
17```bash
18go get -u github.com/Azure/go-autorest/autorest/adal
19```
20
21## Usage
22
23An Active Directory application is required in order to use this library. An application can be registered in the [Azure Portal](https://portal.azure.com/) by following these [guidelines](https://docs.microsoft.com/azure/active-directory/develop/active-directory-integrating-applications) or using the [Azure CLI](https://github.com/Azure/azure-cli).
24
25### Register an Azure AD Application with secret
26
27
281. Register a new application with a `secret` credential
29
30 ```
31 az ad app create \
32 --display-name example-app \
33 --homepage https://example-app/home \
34 --identifier-uris https://example-app/app \
35 --password secret
36 ```
37
382. Create a service principal using the `Application ID` from previous step
39
40 ```
41 az ad sp create --id "Application ID"
42 ```
43
44 * Replace `Application ID` with `appId` from step 1.
45
46### Register an Azure AD Application with certificate
47
481. Create a private key
49
50 ```
51 openssl genrsa -out "example-app.key" 2048
52 ```
53
542. Create the certificate
55
56 ```
57 openssl req -new -key "example-app.key" -subj "/CN=example-app" -out "example-app.csr"
58 openssl x509 -req -in "example-app.csr" -signkey "example-app.key" -out "example-app.crt" -days 10000
59 ```
60
613. Create the PKCS12 version of the certificate containing also the private key
62
63 ```
64 openssl pkcs12 -export -out "example-app.pfx" -inkey "example-app.key" -in "example-app.crt" -passout pass:
65
66 ```
67
684. Register a new application with the certificate content form `example-app.crt`
69
70 ```
71 certificateContents="$(tail -n+2 "example-app.crt" | head -n-1)"
72
73 az ad app create \
74 --display-name example-app \
75 --homepage https://example-app/home \
76 --identifier-uris https://example-app/app \
77 --key-usage Verify --end-date 2018-01-01 \
78 --key-value "${certificateContents}"
79 ```
80
815. Create a service principal using the `Application ID` from previous step
82
83 ```
84 az ad sp create --id "APPLICATION_ID"
85 ```
86
87 * Replace `APPLICATION_ID` with `appId` from step 4.
88
89
90### Grant the necessary permissions
91
92Azure relies on a Role-Based Access Control (RBAC) model to manage the access to resources at a fine-grained
93level. There is a set of [pre-defined roles](https://docs.microsoft.com/azure/active-directory/role-based-access-built-in-roles)
94which can be assigned to a service principal of an Azure AD application depending of your needs.
95
96```
97az role assignment create --assigner "SERVICE_PRINCIPAL_ID" --role "ROLE_NAME"
98```
99
100* Replace the `SERVICE_PRINCIPAL_ID` with the `appId` from previous step.
101* Replace the `ROLE_NAME` with a role name of your choice.
102
103It is also possible to define custom role definitions.
104
105```
106az role definition create --role-definition role-definition.json
107```
108
109* Check [custom roles](https://docs.microsoft.com/azure/active-directory/role-based-access-control-custom-roles) for more details regarding the content of `role-definition.json` file.
110
111
112### Acquire Access Token
113
114The common configuration used by all flows:
115
116```Go
117const activeDirectoryEndpoint = "https://login.microsoftonline.com/"
118tenantID := "TENANT_ID"
119oauthConfig, err := adal.NewOAuthConfig(activeDirectoryEndpoint, tenantID)
120
121applicationID := "APPLICATION_ID"
122
123callback := func(token adal.Token) error {
124 // This is called after the token is acquired
125}
126
127// The resource for which the token is acquired
128resource := "https://management.core.windows.net/"
129```
130
131* Replace the `TENANT_ID` with your tenant ID.
132* Replace the `APPLICATION_ID` with the value from previous section.
133
134#### Client Credentials
135
136```Go
137applicationSecret := "APPLICATION_SECRET"
138
139spt, err := adal.NewServicePrincipalToken(
140 *oauthConfig,
141 appliationID,
142 applicationSecret,
143 resource,
144 callbacks...)
145if err != nil {
146 return nil, err
147}
148
149// Acquire a new access token
150err = spt.Refresh()
151if (err == nil) {
152 token := spt.Token
153}
154```
155
156* Replace the `APPLICATION_SECRET` with the `password` value from previous section.
157
158#### Client Certificate
159
160```Go
161certificatePath := "./example-app.pfx"
162
163certData, err := ioutil.ReadFile(certificatePath)
164if err != nil {
165 return nil, fmt.Errorf("failed to read the certificate file (%s): %v", certificatePath, err)
166}
167
168// Get the certificate and private key from pfx file
169certificate, rsaPrivateKey, err := decodePkcs12(certData, "")
170if err != nil {
171 return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
172}
173
174spt, err := adal.NewServicePrincipalTokenFromCertificate(
175 *oauthConfig,
176 applicationID,
177 certificate,
178 rsaPrivateKey,
179 resource,
180 callbacks...)
181
182// Acquire a new access token
183err = spt.Refresh()
184if (err == nil) {
185 token := spt.Token
186}
187```
188
189* Update the certificate path to point to the example-app.pfx file which was created in previous section.
190
191
192#### Device Code
193
194```Go
195oauthClient := &http.Client{}
196
197// Acquire the device code
198deviceCode, err := adal.InitiateDeviceAuth(
199 oauthClient,
200 *oauthConfig,
201 applicationID,
202 resource)
203if err != nil {
204 return nil, fmt.Errorf("Failed to start device auth flow: %s", err)
205}
206
207// Display the authentication message
208fmt.Println(*deviceCode.Message)
209
210// Wait here until the user is authenticated
211token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
212if err != nil {
213 return nil, fmt.Errorf("Failed to finish device auth flow: %s", err)
214}
215
216spt, err := adal.NewServicePrincipalTokenFromManualToken(
217 *oauthConfig,
218 applicationID,
219 resource,
220 *token,
221 callbacks...)
222
223if (err == nil) {
224 token := spt.Token
225}
226```
227
228#### Username password authenticate
229
230```Go
231spt, err := adal.NewServicePrincipalTokenFromUsernamePassword(
232 *oauthConfig,
233 applicationID,
234 username,
235 password,
236 resource,
237 callbacks...)
238
239if (err == nil) {
240 token := spt.Token
241}
242```
243
244#### Authorization code authenticate
245
246``` Go
247spt, err := adal.NewServicePrincipalTokenFromAuthorizationCode(
248 *oauthConfig,
249 applicationID,
250 clientSecret,
251 authorizationCode,
252 redirectURI,
253 resource,
254 callbacks...)
255
256err = spt.Refresh()
257if (err == nil) {
258 token := spt.Token
259}
260```
261
262### Command Line Tool
263
264A command line tool is available in `cmd/adal.go` that can acquire a token for a given resource. It supports all flows mentioned above.
265
266```
267adal -h
268
269Usage of ./adal:
270 -applicationId string
271 application id
272 -certificatePath string
273 path to pk12/PFC application certificate
274 -mode string
275 authentication mode (device, secret, cert, refresh) (default "device")
276 -resource string
277 resource for which the token is requested
278 -secret string
279 application secret
280 -tenantId string
281 tenant id
282 -tokenCachePath string
283 location of oath token cache (default "/home/cgc/.adal/accessToken.json")
284```
285
286Example acquire a token for `https://management.core.windows.net/` using device code flow:
287
288```
289adal -mode device \
290 -applicationId "APPLICATION_ID" \
291 -tenantId "TENANT_ID" \
292 -resource https://management.core.windows.net/
293
294```
View as plain text