Issues with OpenID / Office365

@Rozpalacz123 if you are talking about “add support for client validation in the OpenID Connect authenticator” this has been done yes. See the new property “oidc.secret” in https://extensions.xwiki.org/xwiki/bin/view/Extension/OpenID%20Connect/OpenID%20Connect%20Authenticator/.

My wiki works with azure now :smiley:

But I have a question. When user login first time account is created but only with First Name and Last name filled. Is there any option to fill other data like email?
I have try with:

oidc.user.emailFormater=${oidc.user.unique_name}
oidc.user.mailFormater=${oidc.user.unique_name}
oidc.user.email=${oidc.user.unique_name}
oidc.user.mail=${oidc.user.unique_name}

but no lack.

This is my JSON response.

{
    "aio": "kjaldjsfhkjsadhflkdhsafkjadhsfa",
    "amr": "[\"pwd\"]",
    "family_name": "Picasso",
    "given_name": "Pablo",
    "ipaddr": "11.12.113.144",
    "name": "Pablo Picasso",
    "oid": "234234-2343-4343-43434-2342342",
    "onprem_sid": "234234234-23-423-4-234-2-34-234",
    "sub": "234233q45rtferfwverfwgw45grfg45g45",
    "tid": "sdfkjgasdhjfgasjdhfgashjdfgasdhjf",
    "unique_name": "pablo.picasso@company.com",
    "upn": "pablo.picasso@company.com",
    "uti": "kajshdfkljahsdfkjahsdkjfahsd",
    "ver": "1.0"
}

By default you get all the standard OIDC fields filled in the XWiki user. In your JSON you only have the first and last name. You can see https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims for the list of standard OIDC claims.

To fill custom properties you can use the configuration oidc.user.mapping in xwiki.properties file (since 1.18). See https://extensions.xwiki.org/xwiki/bin/view/Extension/OpenID%20Connect/OpenID%20Connect%20Authenticator/#Hxwiki.properties for more details.

below works for me with email :slight_smile:
oidc.user.mapping=email=${oidc.user.unique_name}

Is there any option to get Xwiki field name for mapping like ‘email’ above? For “Blog Feed”, “Company” (i guess for it will be ‘company’) :slight_smile:

In the admin of the wiki you have the configuration of the “User Profile” in which you can find the various fields.

Yes I know, but can I found mapping somewhere for example for field “Blog Feed”?
I it will be:
oidc.user.mapping=BlogFeed=${oidc.user.unique_name}

?

If you look at the User Profile administration as I suggested you will notice that there is a field named “blogfeed” so that’s what you should use. You also have a link to the user class where you can see all the existing fields id and display name and add new ones if needed.

OK, everything works great but when I try get info from graph v1.0 (because I need more info about user info like mailNickname

oidc.endpoint.userinfo=https://graph.microsoft.com/v1.0/me

i get error.

response ({
  "error": {
    "code": "BadRequest",
    "message": "The MIME type 'text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2' requires a '/' character between type and subtype, such as 'text/plain'.",
    "innerError": {
      "request-id": "b0aaaeb0-1aaa-4bc2-9aaa-511aaaaae4ae",
      "date": "2020-03-19T17:17:13"
    }
  }
}
)

This is because we send in request header:

Accept: text/html, image/gif, image/jpeg, *; q=.2, /; q=.2

Is there any option to send
Accept: application/json
?

In my opinion it makes more sense because we always get JSON.
Looks very very easy to fix in JAVA code :slight_smile:

See resolution in:
StackOverflow - Bad Request 400 when making API call to Microsoft Graph

I don’t know Java but i think header should be added here:

OIDCUserManager.java

line 177

UserInfoRequest userinfoRequest =
                new UserInfoRequest(userInfoEndpoint, this.configuration.getUserInfoEndPointMethod(), accessToken);
            HTTPRequest userinfoHTTP = userinfoRequest.toHTTPRequest();
            userinfoHTTP.setHeader("User-Agent", this.getClass().getPackage().getImplementationTitle() + '/'
                + this.getClass().getPackage().getImplementationVersion());

As far as I understand the request does not send any Accept right now so no idea where what you get is coming from. Also the authenticator is using oauth2-oidc-sdk library for this so this discussion should go there instead since it’s not the authenticator job to decide this IMO.

I get it from logs :slight_smile: I see JSON that is returned.

It is set as default for this method. If nothing is send then default Accepted is text… (info from stackoverflow)

So there is no option to add one line as below?

UserInfoRequest userinfoRequest =
                new UserInfoRequest(userInfoEndpoint, this.configuration.getUserInfoEndPointMethod(), accessToken);
            HTTPRequest userinfoHTTP = userinfoRequest.toHTTPRequest();
            userinfoHTTP.setHeader("User-Agent", this.getClass().getPackage().getImplementationTitle() + '/'
                + this.getClass().getPackage().getImplementationVersion());

// add line below
   userinfoHTTP.setHeader("Accept", "application/json");

This is my config which is checking header Accept on MS site:

oidc.endpoint.provider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
oidc.endpoint.userinfo=https://graph.microsoft.com/v1.0/me

With other config like below MS not verify header Accept - we can send everything there:

oidc.xwikiprovider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/token
oidc.endpoint.userinfo=https://login.microsoftonline.com/{tenant}/openid/userinfo

or

oidc.xwikiprovider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
oidc.endpoint.userinfo=https://graph.microsoft.com/oidc/userinfo

everything works because there header Accept is not verifying on MS site. But I can not get all info about user in this way :frowning:

What is indicated on stackoverflow is that POSTman set this Accept by default but that’s not what is used here. Maybe you have some proxy which does that or maybe a proxy in front of https://graph.microsoft.com/v1.0/me.

It’s not really the question, of course it’s easy to set a custom Accept but it would be more interresting to:

  • understand why you end up with that Accept
  • understand why it’s not set explicitly in oauth2-oidc-sdk, this suggest the OIDC specification does not indicate any Accept`

version 4.12 (2015-03-14)
* HTTPRequest adds support for arbitrary headers.
* HTTPResponse adds support for arbitrary headers.

.
.

So can you create a custom jar or any other file with this small change (one line) for me that i can use in xwiki? I will ulopad it somewhere in wiki :slight_smile: Don’t know where yet. I installed it from Manager. I can Pay you for that, because I don’t know Java :frowning:

I asked my IT friends but they had a problem after import ext. from github and couldn’t compile :frowning:

Almost. I get an error now:

Caused by: com.nimbusds.oauth2.sdk.ParseException: Couldn't parse UserInfo claims: Missing or invalid "sub" claim
	at com.nimbusds.openid.connect.sdk.UserInfoSuccessResponse.parse(UserInfoSuccessResponse.java:243)
	at com.nimbusds.openid.connect.sdk.UserInfoResponse.parse(UserInfoResponse.java:73)

I see there is a need to edit also oauth-2.0-sdk-with-openid-connect-extensions. Lot lot of changes :frowning:

There are more fields that not appear in JSON :frowning:
Maybe it is a good idea to create oauth-2.0 for MS Graph 1.0?

I don’t know how can I contact owner of this extension. Any ideas?

OK works like a charm :slight_smile:
(Sorry for my bad code but I don’t know JAVA)

To make it works with endpoint userinfo:
oidc.endpoint.userinfo=https://graph.microsoft.com/v1.0/me

we need 2 changes:

FIRST:
in file:

oidc-authenticator\src\main\java\org\xwiki\contrib\oidc\auth\internal\OIDCUserManager.java

line
line 177

userinfoHTTP.setHeader("User-Agent", this.getClass().getPackage().getImplementationTitle() + '/'
     + this.getClass().getPackage().getImplementationVersion());
// added line below
userinfoHTTP.setHeader("Accept", "application/json");

SECOND:
in below file (for sure version 2.63 - the newest version is not compatible with XWiki):

oauth-2.0-sdk-with-openid-connect-extensions\src\main\java\com\nimbusds\openid\connect\sdk\UserInfoSuccessResponse.java

import
import net.minidev.json.JSONObject;

line: 238
from:

try {
    claimsSet = new UserInfo(httpResponse.getContentAsJSONObject());			
} catch (Exception e) {

to:

try {
    JSONObject j = httpResponse.getContentAsJSONObject();
    j.put("sub", "abcdefgh");
    claimsSet = new UserInfo(j);
} catch (Exception e) {

Any idea idea why this is needed ? It does not seems to be doing anything else than adding a “sub” property to the received JSON.

Because “sub” not exists in JSON response in Graph userinfo:
https://graph.microsoft.com/v1.0/me

Below fields are in standard response:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
    "businessPhones": [
        "+1 412 555 0109"
    ],
    "displayName": "Megan Bowen",
    "givenName": "Megan",
    "jobTitle": "Auditor",
    "mail": "MeganB@M365x214355.onmicrosoft.com",
    "mobilePhone": null,
    "officeLocation": "12/1110",
    "preferredLanguage": "en-US",
    "surname": "Bowen",
    "userPrincipalName": "MeganB@M365x214355.onmicrosoft.com",
    "id": "48d31887-5fad-4d73-a9f5-3c356e68a038"
}

And because “sub” is mandatory:

Caused by: com.nimbusds.oauth2.sdk.ParseException: Couldn't parse UserInfo claims: Missing or invalid "sub" claim
	at com.nimbusds.openid.connect.sdk.UserInfoSuccessResponse.parse(UserInfoSuccessResponse.java:248)
	at com.nimbusds.openid.connect.sdk.UserInfoResponse.parse(UserInfoResponse.java:73)

or if I set it to empty string:

Caused by: java.lang.IllegalArgumentException: The value must not be null or empty string
	at com.nimbusds.oauth2.sdk.id.Identifier.<init>(Identifier.java:92)
	at com.nimbusds.oauth2.sdk.id.Subject.<init>(Subject.java:39)

So there must be a value assigned to “sub”.

So I verify all my changes and I finally modify everything only in two files of
oauth-2.0-sdk-with-openid-connect-extensions
BTW (try to implement changes in lastest version of this ext but it is not compatibile with xwiki, so I use the same that is already on xwiki: v6.23)

I modified two files:
.
.
.
FIRST

\oauth-2.0-sdk-with-openid-connect-extensions\src\main\java\com\nimbusds\openid\connect\sdk\UserInfoSuccessResponse.java
line: 238

from:

	    if (ct.match(CommonContentTypes.APPLICATION_JSON)) {
		
			UserInfo claimsSet;
			
			try {
				claimsSet = new UserInfo(httpResponse.getContentAsJSONObject());
				
			} catch (Exception e) {
				
				throw new ParseException("Couldn't parse UserInfo claims: " + 
					                 e.getMessage(), e);
			}
			
			response = new UserInfoSuccessResponse(claimsSet);
		}

to:

		if (ct.match(CommonContentTypes.APPLICATION_JSON)) {
		
			UserInfo claimsSet;
			
			try {
				JSONObject j = httpResponse.getContentAsJSONObject();
				
				if (!j.containsKey("sub") && j.containsKey("id")) {
					j.put("sub", j.get("id").toString());
				}
				
				claimsSet = new UserInfo(j);
				
			} catch (Exception e) {
				
				throw new ParseException("Couldn't parse UserInfo claims: " + 
					                 e.getMessage(), e);
			}
			
			response = new UserInfoSuccessResponse(claimsSet);
		}

I decided to assign “sub” from “id” because “id” is mostly uses in newer verson of openid userinfo (instead of “sub”).
.
.
.
SECOND

oauth-2.0-sdk-with-openid-connect-extensions\src\main\java\com\nimbusds\oauth2\sdk\http\HTTPRequest.java
line: 800

by adding new line:

conn.addRequestProperty("Accept", "application/json");

so it looks now:

	conn.addRequestProperty("Accept", "application/json");
	conn.setRequestMethod(method.name());
	conn.setConnectTimeout(connectTimeout);
	conn.setReadTimeout(readTimeout);
	conn.setInstanceFollowRedirects(followRedirects);

I have tested header set like abowe and all each below methods worked:

oidc.endpoint.provider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
oidc.endpoint.userinfo=https://graph.microsoft.com/v1.0/me

.

oidc.xwikiprovider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/token
oidc.endpoint.userinfo=https://login.microsoftonline.com/{tenant}/openid/userinfo

.

oidc.xwikiprovider=https://login.microsoftonline.com/{tenant}/oauth2
oidc.endpoint.authorization=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
oidc.endpoint.token=https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
oidc.endpoint.userinfo=https://graph.microsoft.com/oidc/userinfo

It really seems you are trying hard to make an endpoint which have nothing to do with OpenID connect protocol fit in the standard code which does not make much sense.

A probably much better direction would be to use the extension mechanism provided by the authenticator (see https://extensions.xwiki.org/xwiki/bin/view/Extension/OpenID%20Connect/OpenID%20Connect%20Authenticator/#HListeners) and write a special component which request https://graph.microsoft.com/v1.0/me and update the user accordingly.

but was much more simpler to modify two files and everything works perfect :slight_smile:

Besides I know from official site that MS is working on adding “sub” to /me because many people requesting it. That will solve one problem with
oauth-2.0-sdk-with-openid-connect-extensions. So it will be only one problem with header Accept. Will be great if you could although add possibility to set header in xwiki.properties file. Can I count on you in that? :slight_smile:
Then all problems will be solved :slight_smile:

@tmortagne added a header modification functionality in the update 1.22. Thank you for that! :smiling_face_with_three_hearts:
@Rozpalacz123 So now we need to push microsoft to implement custom properties or the sub claim quickly! :grin:

Please everyone coming here, wanting microsoft to add the sub claim to Microsoft Graph /me endpoint please vote on this Uservoice idea: