diff --git a/admin-ui/pom.xml b/admin-ui/pom.xml deleted file mode 100644 index 641b32f..0000000 --- a/admin-ui/pom.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - 4.0.0 - - com.xwiki.integration-azure-oauth - integration-azure-oauth-parent - 1.9.1-SNAPSHOT - - - integration-azure-oauth-admin-ui - xar - - Administration Classes for Microsoft Azure Active Directory Single Sign-On (SSO) (pro) - This extension supports the authentication to the wiki using Azure Active Directory - - - - Configuration Pages for Microsoft Azure Active Directory Single Sign-On (SSO) (Pro) - - true - true - other - - - AzureADAdmin.WebHome - - - AzureADAdmin.AzureADConfig - - - - - - com.xwiki.licensing - application-licensing-licensor-api - ${licensing.version} - - - com.xwiki.integration-azure-oauth - integration-azure-oauth-api - ${project.version} - - - com.xwiki.identity-oauth - identity-oauth-ui - ${identity.oauth.version} - xar - - - diff --git a/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigClass.xml b/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigClass.xml deleted file mode 100644 index 9dc7a6f..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigClass.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - AzureADAdmin - AzureADConfigClass - - - 0 - xwiki:XWiki.Admin - xwiki:AzureADAdmin.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - - <comment/> - <minorEdit>false</minorEdit> - <syntaxId>xwiki/2.1</syntaxId> - <hidden>true</hidden> - <content/> - <class> - <name>AzureADAdmin.AzureADConfigClass</name> - <customClass/> - <customMapping/> - <defaultViewSheet/> - <defaultEditSheet/> - <defaultWeb/> - <nameField/> - <validationScript/> - <tenantid> - <customDisplay/> - <disabled>0</disabled> - <name>tenantid</name> - <number>1</number> - <picker>0</picker> - <prettyName>tenant id</prettyName> - <size>60</size> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.StringClass</classType> - </tenantid> - </class> -</xwikidoc> diff --git a/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigSheet.xml b/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigSheet.xml deleted file mode 100644 index 146c9c0..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/AzureADConfigSheet.xml +++ /dev/null @@ -1,178 +0,0 @@ -<?xml version="1.1" encoding="UTF-8"?> - -<!-- - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. ---> - -<xwikidoc version="1.5" reference="AzureADAdmin.AzureADConfigSheet" locale=""> - <web>AzureADAdmin</web> - <name>AzureADConfigSheet</name> - <language/> - <defaultLanguage/> - <translation>0</translation> - <creator>xwiki:XWiki.Admin</creator> - <parent>AzureADAdmin.WebHome</parent> - <author>xwiki:XWiki.Admin</author> - <contentAuthor>xwiki:XWiki.Admin</contentAuthor> - <version>1.1</version> - <title>#if($doc.fullName=="AzureADAdmin.AzureADConfigSheet")Azure AD Config Sheet#else $doc.title #end - - false - xwiki/2.1 - true - {{include reference="IdentityOAuth.IdentityOAuthConfigMacros" /}} - -{{velocity output="false"}} -#macro (getLinkTranslations $registrationHint $documentationHint $outlookHint) - ## Register for OAuth access on the Microsoft Azure portal. - #getTranslation('communicate.hint.linkLabel', 'xml', $translation) - #set ($portalLink = 'https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps') - #set ($registrationLink = "<a href='${portalLink}'>${translation}</a>") - #tp('communicate.hint', ['__LINK__'], 'xml', $translation) - #set ($registrationHint = $translation.replace('__LINK__', $registrationLink)) - ## Installation instruction. - #getTranslation('communicate.hint2.linkLabel', 'xml', $translation) - #set ($documentationLink = "<a href='${productPage}#documentation'>${translation}</a>") - #tp('communicate.hint2', ['__LINK__'], 'xml', $translation) - #set ($documentationHint = $translation.replace('__LINK__', $documentationLink)) - ## Use outlook for avatars. - #getTranslation('scope_avatar.onlyOutlook.linkLabel', 'xml', $translation) - #set ($outlookLink = - "<a href='https://docs.microsoft.com/en-us/graph/known-issues#photo-restrictions'>${translation}</a>") - #tp('scope_avatar.onlyOutlook', ['__LINK__'], 'xml', $translation) - #set ($outlookHint = $translation.replace('__LINK__', "${outlookLink}")) -#end -{{/velocity}} - -{{velocity}} -#if(!$xwiki.hasAdminRights()) - Admin rights are needed. -#else - ## defines formId, propNamePrefixIO, configDoc, objIO, objO - ## #set($configDocName="AzureAD.AzureADConfig") - ## set($providerHint = "AzureAD") - ## #set($productPage = "https://store.xwiki.com/xwiki/bin/view/Extension/AzureADIntegration") - #initConfigObjects(${configDocName}, ${extraObjectClassPropPrefixes}, ${translationPrefix}) - ## use stylesheet and JavaScript extensions - #ioIncludeUIX() - #getLinkTranslations($registrationHint $documentationHint $outlookHint) - {{html clean="false" wiki=false}} - <script>window.identityOAuthProvider = "${providerHint}";</script> - <p>#t('config.explanation')</p> - - <form id="$formId" method="post" action="$xwiki.getURL($configDoc, 'saveandcontinue')" class="xform"> - <dl> - <dt>#displayInput ("active", $objIO) <label for="${propNamePrefixIO}_active">#t ("active")</label></dt> - <dd></dd> - </dl> - - <fieldset> - <legend>#t ('communicate')</legend> - - <dl> - <dt><span class="xHint"> - $registrationHint<br> - $documentationHint</span> - </dt> - <dd></dd> - <dt><label for="${propNamePrefixIO}_clientid">#t ('clientid')</label> - <span class="xHint">#t ("clientid.hint")</span></dt> - <dd> #displayInput ('clientid', $objIO)</dd> - - <dt><label for="${propNamePrefixIO}_secret">#t ('secret')</label> - <span class="xHint">#t("secret.hint")</span></dt> - <dd> #displayInput ("secret", $objIO)</dd> - - #foreach($x in $extraObjectClassPropPrefixes) - <dt><label for="${x[2]}_0_${x[1]}">#t ($x[1])</label> - <span class="xHint">#t ("${x[1]}.hint")</span></dt> - <dd> #displayInput ("${x[1]}", $x[0])</dd> - #end - - <dt><label for="${propNamePrefixIO}_redirectUrl">#t ('redirectUrl')</label> - <span class="xHint">#t ("redirectUrl.hint")</span> - </dt> - #* - Four cases: - - redirectUrl browsers' matches servers' - - 1) value as expected - - redirectUrl browsers' unequal servers' - - 2) value as browser's - - 3) value as server's - - 4) independent - *# - #calcReturnUrlsJS() - <dd> #renderRedirectUrlInputAndHints() - </dd> - - ## checkboxes for scope, needs JS - <dt><label>#t ('scope')</label> - <span class="xHint">#t ('scope.hint')</span></dt> - <dd> - <label title="#t ('checkbox_mandatory')"> - <input type="checkbox" name="scope_openid " disabled="true" checked class="mandatory">#t ('scope_identity')</label> - <label title="#t ('checkbox_mandatory')"> - <input type="checkbox" name="scope_User.Read" disabled="true" checked class="mandatory">#t ("scope_email")</label><br/> - <label title="#t('checkbox_notyetdone')"> - <input type="checkbox" name="scope_User.ReadBasic.All">#t ('scope_avatar')</label> - #set($p=$configDocName.length()+1) - <input type="hidden" name="${propNamePrefixIO.substring($p)}_scope" value="${objIO.getValue('scope')}"/> - ($outlookHint) - </dd> - </dl> - </fieldset> - - ## <fieldset> - ## <legend>#t ('loginbehaviour')</legend> - - ## <dl> - ## TODO: add domains' limitation - - ## TODO: add cookie's support - ## </dl> - ## </fieldset> - - - ## Hidden form elements - #set ($params = "editor=${escapetool.url(${editor})}&amp;section=${escapetool.url(${section})}") - #set ($params = "${params}&amp;space=${escapetool.url(${currentSpace})}") - #set ($continueURL = $xwiki.getURL($currentDoc, 'admin', $params)) - <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}"/> - <input type="hidden" name="xcontinue" value="${continueURL}"/> - <input type="hidden" name="xredirect" value="${continueURL}"/> - - ## submit - <div class="bottombuttons"> - <p><span id="warningIncomplete">#t("warningIncomplete")</span>&nbsp;</p> - <p class="admin-buttons"> - <span class="buttonwrapper"> - <input class="button" type="submit" name="formactionsac" - value="$escapetool.xml($services.localization.render('admin.save'))"/> - </span> - </p> - </div> - </form> - <div id="appOnNowWhat"> - <p>#t ('nowWhat1')</p> - <p>#t ('nowWhat2')</p> - </div> -#end -{{/html}} -{{/velocity}} - diff --git a/admin-ui/src/main/resources/AzureADAdmin/Install.xml b/admin-ui/src/main/resources/AzureADAdmin/Install.xml deleted file mode 100644 index 71349e4..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/Install.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - AzureADAdmin - Install - - - 0 - xwiki:XWiki.Admin - AzureADAdmin.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - AzureADAdmin Installation - - false - xwiki/2.0 - true - {{velocity}} -#if(!$xwiki.hasAdminRights()) - You are running this script as a non admin. It will have no effect. Login as admin. -#else - This script automatically sets the owner of the pages in the AzureADAdmin Application. - This will allow the priviledged scripts included in them to work. -#end -#if($request.confirm=="1") - Assigning programming rights to the following pages: -#else - [[Confirm assigning programming rights to the following pages:>>$doc.fullName?confirm=1]] -#end - -#foreach($item in $xwiki.searchDocuments("where doc.web='AzureADAdmin'")) -* $item #if($request.confirm=="1") $xwiki.getDocument($item).save() #end - -#end - -#set($transdoc = $xwiki.getDocument("XWiki.XWikiPreferences")) -#set($ok = $transdoc.setTitle($transdoc.getTitle())) -#set($ok = $transdoc.use("XWiki.XWikiPreferences")) -#set($transprefs = $transdoc.getValue("documentBundles")) -#if($transprefs.indexOf("AzureADAdmin.Translations")==-1) - #if($request.confirm=="1") - #set($transprefs = "${transprefs},AzureADAdmin.Translations") - #set($ok = $transdoc.set("documentBundles", $transprefs)) - #set($ok = $transdoc.save()) - #end -* Added translation bundle to XWiki Preferences -#end -{{/velocity}} - diff --git a/admin-ui/src/main/resources/AzureADAdmin/Translations.de.xml b/admin-ui/src/main/resources/AzureADAdmin/Translations.de.xml deleted file mode 100644 index fdb1c38..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/Translations.de.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - AzureADAdmin - Translations - de - en - 1 - xwiki:XWiki.Admin - AzureADAdmin.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - AzureADAdmin Translations (Deutsch/German) - - false - plain/1.0 - true - admin.azureAD=Azure AD -# Login page -azureADAdmin.loginWithAzureAD = Login mit Azure Active Directory - -# Admin (extras compared to IdentityOAuth/Translations -azureADAdmin.config.heading=AzureAD Integration -azureADAdmin.AzureADConfigClass_config.explanation=XWiki kann die Benutzer von eines Azure Active Directory Installation erkennen. -azureAD.extension.name=Microsoft Azure Active Directory Single Sign-On (SSO) (Pro) - -azureADAdmin.AzureADConfigClass_communicate=Verbindungen mit den Diensten von Azure Active Directory -azureADAdmin.AzureADConfigClass_communicate.hint=Damit Sie Azure AD Integration aktivieren können, brauchen Sie {0} und die Kundenidentifizierung, Halteridentifizierung und Geheimschlüssel hier einfügen. -azureADAdmin.AzureADConfigClass_communicate.hint.linkLabel=eine OAuth Applikation für OAuth Zugang bei der Microsoft Azure Console registrieren -azureADAdmin.AzureADConfigClass_communicate.hint2=Sie erhalten mehr Information dazu bei den {0}. -azureADAdmin.AzureADConfigClass_communicate.hint2.linkLabel=Installationsanweisungen - -azureADAdmin.AzureADConfigClass_tenantid=Halteridentifikator (Tenant-ID) -azureADAdmin.AzureADConfigClass_tenantid.hint=In dem Übersicht von Azure zu finden. - - -azureADAdmin.AzureADConfigClass_nowWhat1=Nachdem du die Konfiguration zu Ende geführt hast, solltest du ein Log-out und Log-in machen, indem du auf "Login mit Azure Active Directory" klickst.\ -azureADAdmin.AzureADConfigClass_nowWhat2=Im Fall von technische Schwierigkeiten kann das XWiki Support helfen, support@xwikisas.com. - -## a single change for avatar's setting -azureADAdmin.AzureADConfigClass_scope_avatar.onlyOutlook = Diese Funktion ist nur aktiv mit Konten, die Outlook benutzen können, eine {0}bekannte{1} Begrenzung - - diff --git a/admin-ui/src/main/resources/AzureADAdmin/Translations.fr.xml b/admin-ui/src/main/resources/AzureADAdmin/Translations.fr.xml deleted file mode 100644 index b7f12a0..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/Translations.fr.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - AzureADAdmin - Translations - fr - en - 1 - xwiki:XWiki.Admin - AzureADAdmin.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - Azure AD Translations (Français/French) - - false - plain/1.0 - true - admin.azureAD=Azure AD -# Login page -azureADAdmin.loginWithAzureAD = Connexion avec Azure Active Directory - -# Admin (extras compared to IdentityOAuth/Translations -azureADAdmin.config.heading=Configuration de AzureAD -azureADAdmin.AzureADConfigClass_config.explanation=XWiki peut être intégré pour permettre la connexion des utilisateurs en utilisant ceux d'Azure Active Directory. -azureAD.extension.name=Microsoft Azure Active Directory Single Sign-On (SSO) (Pro) - -azureADAdmin.AzureADConfigClass_communicate=Communication avec les services Azure Active Directory -azureADAdmin.AzureADConfigClass_communicate.hint=Pour activer l''intégration Azure AD vous devez {0} and insérer ici votre identifiant de client, de locataire (tenant) et la clé-secrete. -azureADAdmin.AzureADConfigClass_communicate.hint.linkLabel=enregistrez une application OAuth sur la console Azure -azureADAdmin.AzureADConfigClass_communicate.hint2=Pour plus d''informations, veuillez vous référer aux {0}. -azureADAdmin.AzureADConfigClass_communicate.hint2.linkLabel=instructions d''installation - -azureADAdmin.AzureADConfigClass_tenantid=Identifiant de locataire (tenant-ID) -azureADAdmin.AzureADConfigClass_tenantid.hint=Ainsi que fourni dans la vue d'ensemble Azure - - -azureADAdmin.AzureADConfigClass_nowWhat1=Une fois la configuration effectuée et enregistrée, veuillez vous déconnecter et vous connecter en cliquant "Connexion avec Azure Active Directory". -azureADAdmin.AzureADConfigClass_nowWhat2=Si vous avez des difficultés, veuillez contacter le support technique support@xwikisas.com . - -## a single change for avatar's setting -azureADAdmin.AzureADConfigClass_scope_avatar.onlyOutlook = ne fonctionne qu''avec les comptes licensiés pour l''usage de'Outlook, une {0}limitation connue{1} - - diff --git a/admin-ui/src/main/resources/AzureADAdmin/WebHome.xml b/admin-ui/src/main/resources/AzureADAdmin/WebHome.xml deleted file mode 100644 index 40773c8..0000000 --- a/admin-ui/src/main/resources/AzureADAdmin/WebHome.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - AzureADAdmin - WebHome - - - 0 - xwiki:XWiki.Admin - xwiki:Main.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - Microsoft Azure Active Directory Single Sign-On (SSO) - - false - xwiki/2.1 - true - {{velocity}} -#set ($reference = $services.model.createDocumentReference("xwiki", ["AzureADAdmin"], "WebPreferences")) -#if (!$services.licensing.licensor.hasLicensureForEntity($references)) - {{missingLicenseMessage extensionName="azureAD.extension.name"/}} -#else -This space contains the administration code for the Azure Active Directory Integration of XWiki. - This extensions currently allows users to login with XWiki by authorizing the transmission - of profile information from an Azure Active Directory node. It uses the OAuth protocol - and, thus, the OpenID basic derivative. - #end -{{/velocity}} - diff --git a/api/pom.xml b/api/pom.xml index fe65691..5829db6 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -28,8 +28,8 @@ integration-azure-oauth-api jar - Microsoft Azure Active Directory Single-Sign-On (SSO) (pro) API - This extension allows users to authenticate to the wiki using Azure Active Directory + Microsoft Entra ID SSO API + This extension allows users to authenticate to the wiki using Entra ID, formerly known as Azure Active Directory. @@ -52,21 +52,20 @@ javax.servlet-api provided - - com.xwiki.identity-oauth - identity-oauth-api - ${identity.oauth.version} - org.xwiki.platform xwiki-platform-configuration-default ${platform.version} - org.xwiki.commons - xwiki-commons-tool-test-component - ${commons.version} - test + org.xwiki.contrib.oidc + oidc-authenticator + 2.13.4-SNAPSHOT + + + org.xwiki.platform + xwiki-platform-rest-server + ${platform.version} org.xwiki.platform @@ -78,5 +77,11 @@ xwiki-platform-refactoring-api ${platform.version} + + org.xwiki.commons + xwiki-commons-tool-test-component + ${commons.version} + test + diff --git a/api/src/main/java/com/xwiki/azureoauth/AzureADIdentityOAuthProvider.java b/api/src/main/java/com/xwiki/azureoauth/AzureADIdentityOAuthProvider.java deleted file mode 100644 index e80ab7b..0000000 --- a/api/src/main/java/com/xwiki/azureoauth/AzureADIdentityOAuthProvider.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package com.xwiki.azureoauth; - -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Provider; -import javax.inject.Singleton; - -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.slf4j.Logger; -import org.xwiki.component.annotation.Component; -import org.xwiki.extension.ExtensionId; -import org.xwiki.model.reference.DocumentReference; -import org.xwiki.model.reference.DocumentReferenceResolver; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.xpn.xwiki.doc.XWikiDocument; -import com.xwiki.identityoauth.IdentityOAuthException; -import com.xwiki.identityoauth.IdentityOAuthManager; -import com.xwiki.identityoauth.IdentityOAuthProvider; -import com.xwiki.identityoauth.internal.IdentityOAuthConstants; -import com.xwiki.licensing.Licensor; - -/** - * A provider to read identity based on OAuth/OpenID from Microsoft Azure Active Directory. - * - * @version $Id$ - * @since 1.0 - */ -@Component -@Named("AzureAD") -@Singleton -public class AzureADIdentityOAuthProvider implements IdentityOAuthProvider -{ - private static final String TENANT_ID = "tenantid"; - - private static final String PROVIDERHINT = "AzureAD"; - - private static final String EXCEPTIONUNLICENSED = "This extension is not licensed."; - - @Inject - protected DocumentReferenceResolver documentResolver; - - @Inject - protected Logger logger; - - @Inject - protected Provider licensorProvider; - - @Inject - protected Provider identityOAuthManager; - - protected DocumentReference configPageRef; - - @Inject - private AzureADOAuthClient oauthClient; - - private ExtensionId thisExtensionId = - new ExtensionId("com.xwiki.integration-azure-oauth:integration-azure-oauth-ui"); - - private List scopes; - - private boolean active; - - private String tenantId; - - private ThreadLocal currentlyRequestedUrl = new ThreadLocal<>(); - - private ThreadLocal currentlyObtainedJson = new ThreadLocal<>(); - - /** - * Reads initialization from objects expecting key-names clientid, secret, scopes, redirectUrl and tenantid. - * - * @param config the map merging objects from the XWiki-Classes IdentityOAuthConfigClass and AzureADCnfigClass. - */ - public void initialize(Map config) - { - this.active = false; - try { - this.initialize(config.get("active"), config.get("clientid"), config.get("secret"), config.get("scope"), - config.get("redirectUrl"), config.get(TENANT_ID), - config.get("configurationObjectsPage")); - } catch (Exception e) { - logger.warn("Configuration reading failed.", e); - throw new IdentityOAuthException("Trouble at reading configuration.", e); - } - } - - private void initialize(String activeParam, String clientId, String secret, String scopesParam, - String redirectUrl, String tenantId, String configPage) - { - - this.tenantId = tenantId; - - if (scopesParam == null || scopesParam.trim().length() == 0) { - scopes = getMinimumScopes(); - } else { - scopes = makeScopes(Arrays.asList(scopesParam.split(" "))); - } - StringBuilder usedScopes = new StringBuilder(); - for (String s : scopes) { - usedScopes.append(s).append(" "); - } - this.active = activeParam.equals("1") || Boolean.parseBoolean(activeParam); - logger.debug("Configuring class " + this.getClass().getSimpleName() - + " with: \n - scopes: " + scopes + "\n - clientId " + clientId); - - String redir = redirectUrl; - if (redir == null || redir.trim().length() == 0) { - redir = IdentityOAuthConstants.CHANGE_ME_LOGIN_URL; - } - - oauthClient.buildService(clientId, secret, usedScopes.toString(), redir, tenantId); - - configPageRef = documentResolver.resolve(configPage); - logger.debug("MS-AD-Service configured: " + this); - } - - /** - * Verifies that the configured object is activated. - * - * @return true if the verification succeeded. - */ - @Override public boolean isActive() - { - return active; - } - - /** - * Verifies that the license is current every five minutes. - * - * @return true if license was valid in the last five minutes. - */ - @Override public boolean isReady() - { - return licensorProvider.get().hasLicensure(thisExtensionId); - } - - /** - * @return Returns "openid", "User.Read. - */ - @Override - public List getMinimumScopes() - { - return Arrays.asList("openid", "User.Read"); - } - - /** - * @return the reference to the page. - */ - public DocumentReference getConfigPageRef() - { - return configPageRef; - } - - /** - * Receives the reference to the page from the provider. - * - * @param page the string reference - */ - @Override public void setConfigPage(String page) - { - this.configPageRef = documentResolver.resolve(page); - } - - /** - * @return The list of objects' classes to be found in the config page (used for the admin screen). - */ - public List getConfigObjectsClasses() - { - return Arrays.asList("IdentityOAuth.IdentityOAuthConfigClass", - "AzureAD.AzureADConfigClass"); - } - - @Override - public String getRemoteAuthorizationUrl(String redirectUrl) - { - if (!isReady()) { - throw new IllegalStateException(EXCEPTIONUNLICENSED); - } - String authorizationUrl = oauthClient.getAuthorizationUrl(); - logger.debug("Authorization URL: " + authorizationUrl); - return authorizationUrl; - } - - @Override - public Pair createToken(String authCode) - { - if (!isReady()) { - throw new IllegalStateException(EXCEPTIONUNLICENSED); - } - return oauthClient.createToken(authCode); - } - - @Override - public String readAuthorizationFromReturn(Map params) - { - return oauthClient.readAuthorizationFromReturn(params); - } - - /** - * Method for use by sub-classes to perform signed API-calls signed by a current authorization token. - * - * @param url the service URL. - * @return a map of values as parsed by a plain Jackson's {@link ObjectMapper}. - */ - protected Map makeApiCall(String url) - { - Map returnValue; - try { - currentlyRequestedUrl.set(url); - identityOAuthManager.get().requestCurrentToken(getProviderHint()); - returnValue = currentlyObtainedJson.get(); - } catch (Exception e) { - if (e instanceof IdentityOAuthException) { - throw (IdentityOAuthException) e; - } else { - throw new IdentityOAuthException("Trouble at API call.", e); - } - } finally { - currentlyRequestedUrl.remove(); - currentlyObtainedJson.remove(); - } - return returnValue; - } - - /** - * Inner part of {@link #makeApiCall(String)}, using the token. - * - * @param token a currently valid token used to sign the API call - */ - @Override public void receiveFreshToken(String token) - { - try { - String responseBody = oauthClient.performApiRequest(token, currentlyRequestedUrl.get()); - if (logger.isDebugEnabled()) { - logger.debug("Response received: " + responseBody); - } - Map json = new ObjectMapper().readValue(responseBody, Map.class); - currentlyObtainedJson.set(json); - } catch (Exception e) { - throw new IdentityOAuthException("Failure at API call.", e); - } - } - - @Override - public AbstractIdentityDescription fetchIdentityDetails(String token) - { - if (!isReady()) { - throw new IllegalStateException(EXCEPTIONUNLICENSED); - } - return oauthClient.fetchIdentityDetails(token, tenantId); - } - - /** - * Opens the stream of the user image file if it was modified later than the given date. - * - * @param ifModifiedSince Only fetch the file if it is modified after this date. - * @param id the currently collected identity-description. - * @param token the currently valid token. - * @return A triple made of inputstream, media-type, and possibly guessed filename. - */ - public Triple fetchUserImage(Date ifModifiedSince, AbstractIdentityDescription id, - String token) - { - return oauthClient.fetchUserImage(ifModifiedSince, id, token, scopes); - } - - @Override - public boolean enrichUserObject(AbstractIdentityDescription idDescription, XWikiDocument doc) - { - MSADIdentityDescription id = (MSADIdentityDescription) idDescription; - return false; - } - - private List makeScopes(List proposedScopes) - { - return proposedScopes == null || proposedScopes.size() == 0 ? getMinimumScopes() : proposedScopes; - } - - @Override - public String getProviderHint() - { - return PROVIDERHINT; - } - - @Override - public void setProviderHint(String hint) - { - if (!PROVIDERHINT.equals(hint)) { - throw new IllegalStateException("Only \"AzureAD\" is accepted as hint."); - } - } - - @Override - public String validateConfiguration() - { - return "ok"; - } - - static final class MSADIdentityDescription extends AbstractIdentityDescription - { - private final Map json; - - private String issuerId; - - MSADIdentityDescription(Map jsonRecord, String issuerId) - { - this.issuerId = issuerId; - this.json = jsonRecord; - // found entries (2020-10-02): - // businessPhone, displayName, givenName, jobTitle, mail, mobilePhone, officeLocation, - // preferredLanguage, surname, userPrincipalName, id - firstName = json.get("givenName") + ""; - lastName = json.get("surname") + ""; - internalId = json.get("id") + ""; - String providedEmail = (String) json.get("mail"); - if (providedEmail != null) { - emails = Collections.singletonList(providedEmail); - } else { - /* - * AD administrators can create users without email. If this entering here, users that show up - * with a record that has no email will have their email field be defined from the "user-principal", - * username@domain, which may or may not be a valid email address. - */ - emails = Collections.singletonList(json.get("userPrincipalName").toString()); - } - this.userImageUrl = "https://graph.microsoft.com/v1.0/users/" + internalId + "/photo/$value"; - } - - @Override public String getIssuerURL() - { - return "https://login.microsoftonline.com/" + issuerId + "/2.0"; - } - } -} diff --git a/api/src/main/java/com/xwiki/azureoauth/AzureADOAuthClient.java b/api/src/main/java/com/xwiki/azureoauth/AzureADOAuthClient.java deleted file mode 100644 index 525b418..0000000 --- a/api/src/main/java/com/xwiki/azureoauth/AzureADOAuthClient.java +++ /dev/null @@ -1,194 +0,0 @@ -package com.xwiki.azureoauth; -/* - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ - -import java.io.InputStream; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.commons.lang3.tuple.Triple; -import org.slf4j.Logger; -import org.xwiki.component.annotation.Component; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.scribejava.apis.MicrosoftAzureActiveDirectory20Api; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse; -import com.github.scribejava.core.model.OAuthRequest; -import com.github.scribejava.core.model.Response; -import com.github.scribejava.core.model.Verb; -import com.github.scribejava.core.oauth.OAuth20Service; -import com.xwiki.identityoauth.IdentityOAuthException; -import com.xwiki.identityoauth.IdentityOAuthProvider; - -/** - * Microsoft Azure Active Directory authentication client. - * - * @version $Id$ - * @since 1.5 - */ -@Component(roles = AzureADOAuthClient.class) -@Singleton -public class AzureADOAuthClient -{ - private static final String IMAGE_JPEG = "image/jpeg"; - - @Inject - protected Logger logger; - - /** - * The connection service to the azure Active-Directory API. - */ - private OAuth20Service service; - - void buildService(String clientId, String secret, String usedScopes, String redir, String tenantId) - { - service = new ServiceBuilder(clientId) - .apiSecret(secret) - .defaultScope(usedScopes) - //.httpClientConfig(ApacheHttpClientConfig.defaultConfig()) - .callback(redir) - .build(MicrosoftAzureActiveDirectory20Api.custom(tenantId)); - } - - String getAuthorizationUrl() - { - return service.getAuthorizationUrl(); - } - - Pair createToken(String authCode) - { - try { - - OAuth2AccessToken accessToken = service.getAccessToken(authCode); - logger.debug("Obtained accessToken from MS-AD Services."); - // TODO: change return type to an object that contains expiry (and is serializable...) - Date expiry = new Date(System.currentTimeMillis() + 1000L * accessToken.getExpiresIn()); - return new ImmutablePair<>(accessToken.getAccessToken(), expiry); - } catch (OAuth2AccessTokenErrorResponse e) { - String msg = "OAuth trouble at creating token:" + e.getErrorDescription(); - logger.warn(msg, e); - throw new IdentityOAuthException(msg, e); - } catch (Exception e) { - String msg = "Generic trouble at creating Token: " + e; - logger.warn(msg, e); - throw new IdentityOAuthException(msg, e); - } - } - - String readAuthorizationFromReturn(Map params) - { - String errorDescription = "error_description"; - if (params.containsKey(errorDescription)) { - throw new IdentityOAuthException("An error occurred at AzureAD:" - + " " + Arrays.asList(params.get("error")) - + " " + Arrays.asList(params.get(errorDescription))); - } - String codeP = "code"; - String code = params.containsKey(codeP) ? params.get(codeP)[0] : null; - logger.debug("Obtained authorization-code from MS-AD Services."); - return code; - } - - String performApiRequest(String token, String url) throws Exception - { - OAuthRequest request = - new OAuthRequest(Verb.GET, url); - service.signRequest(token, request); - Response response = service.execute(request); - return response.getBody(); - } - - IdentityOAuthProvider.AbstractIdentityDescription fetchIdentityDetails(String token, String issuerId) - { - try { - - OAuthRequest request; - request = new OAuthRequest(Verb.GET, "https://graph.microsoft.com/v1.0/me"); - service.signRequest(token, request); - Response response = service.execute(request); - String responseBody = response.getBody(); - Map json = new ObjectMapper().readValue(responseBody, Map.class); - AzureADIdentityOAuthProvider.MSADIdentityDescription - id = new AzureADIdentityOAuthProvider.MSADIdentityDescription(json, issuerId); - - return id; - } catch (Exception e) { - logger.warn("Trouble at fetchIdentityDetails:", e); - throw new IdentityOAuthException("Trouble at fetchIdentityDetails.", e); - } - } - - Triple fetchUserImage(Date ifModifiedSince, - IdentityOAuthProvider.AbstractIdentityDescription id, String token, List scopes) - { - // add photo metadata - // https://docs.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0 - try { - if (scopes.contains("User.ReadBasic.All") || scopes.contains("User.Read.All")) { - OAuthRequest request; - final List supportedMediaTypes = Arrays.asList(IMAGE_JPEG); - request = new OAuthRequest(Verb.GET, id.userImageUrl); - if (ifModifiedSince != null) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); - sdf.setTimeZone(TimeZone.getTimeZone("CET")); - String ifms = sdf.format(ifModifiedSince); - request.addHeader("If-Modified-Since", ifms); - } - logger.debug("will request " + request); - service.signRequest(token, request); - Response photoResponse = service.execute(request); - String mediaType = photoResponse.getHeader("Content-Type"); - logger.debug("Request done " + mediaType); - if (photoResponse.isSuccessful() - && supportedMediaTypes.contains(mediaType)) - { - String contentDispo = photoResponse.getHeader("Content-Disposition"); - String fileName = "image.jpeg"; - String at = "attachment; "; - if (contentDispo != null && contentDispo.startsWith(at)) { - fileName = contentDispo.substring(at.length()); - } - logger.debug("Obtained content of file " + fileName); - return Triple.of(photoResponse.getStream(), IMAGE_JPEG, fileName); - } else { - logger.warn("Fetching photo failed: " + photoResponse.getMessage()); - if (logger.isDebugEnabled()) { - logger.debug("Photo response: " + photoResponse.getBody()); - } - return null; - } - } - } catch (Throwable e) { - logger.warn("Can't save photo.", e); - } - return null; - } -} diff --git a/api/src/main/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResource.java b/api/src/main/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResource.java new file mode 100644 index 0000000..7f709a8 --- /dev/null +++ b/api/src/main/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResource.java @@ -0,0 +1,77 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.azureoauth.internal.rest; + +import java.net.URI; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; +import org.xwiki.rest.XWikiRestException; +import org.xwiki.velocity.tools.EscapeTool; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xwiki.azureoauth.rest.EntraIDResource; + +/** + * Default implementation of {@link EntraIDResource}. + * + * @version $Id$ + * @since 2.0 + */ +@Component +@Named("com.xwiki.azureoauth.internal.rest.DefaultEntraIDResource") +@Singleton +public class DefaultEntraIDResource implements EntraIDResource +{ + @Inject + private Provider wikiContextProvider; + + @Inject + private Logger logger; + + @Override + public Response xwikiLogin(String redirectDocument) throws XWikiRestException + { + try { + XWikiContext xwikiContext = wikiContextProvider.get(); + XWiki xwiki = xwikiContext.getWiki(); + EscapeTool escapeTool = new EscapeTool(); + + String redirectDocumentURL = xwiki.getURL(escapeTool.xml(redirectDocument), "view", "", xwikiContext); + String parameters = String.format("xredirect=%s&loginLink=1&oidc.skipped=true", redirectDocumentURL); + String loginURL = xwiki.getURL("XWiki.XWikiLogin", "login", parameters, xwikiContext); + + return Response.seeOther(new URI(loginURL)).build(); + } catch (Exception e) { + logger.warn("Failed to generate the log in redirect URL. Root cause: [{}]", + ExceptionUtils.getRootCauseMessage(e)); + throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/api/src/main/java/com/xwiki/azureoauth/rest/EntraIDResource.java b/api/src/main/java/com/xwiki/azureoauth/rest/EntraIDResource.java new file mode 100644 index 0000000..f94ab78 --- /dev/null +++ b/api/src/main/java/com/xwiki/azureoauth/rest/EntraIDResource.java @@ -0,0 +1,50 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.azureoauth.rest; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Response; + +import org.xwiki.rest.XWikiRestComponent; +import org.xwiki.rest.XWikiRestException; +import org.xwiki.stability.Unstable; + +/** + * Provides the API needed by the server in order to skip the OIDC authenticator. + * + * @version $Id$ + * @since 2.0 + */ +@Unstable +@Path("/entraid") +public interface EntraIDResource extends XWikiRestComponent +{ + /** + * Redirect the user to the XWiki login page, skipping the OIDC authenticator. + * @param redirectDocument the page where to be redirected after log in. + * @return status code 303 SEE OTHER and the log in link for redirecting. + * @throws XWikiRestException if an error occurred while building the redirect URL. + */ + @GET + @Path("/login/xwiki/{redirectDocument}") + Response xwikiLogin(@PathParam("redirectDocument") String redirectDocument) throws XWikiRestException; +} diff --git a/api/src/main/java/com/xwiki/azureoauth/script/EntraIDScriptService.java b/api/src/main/java/com/xwiki/azureoauth/script/EntraIDScriptService.java new file mode 100644 index 0000000..9f53974 --- /dev/null +++ b/api/src/main/java/com/xwiki/azureoauth/script/EntraIDScriptService.java @@ -0,0 +1,102 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.azureoauth.script; + +import java.util.stream.Stream; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; +import org.xwiki.model.reference.DocumentReferenceResolver; +import org.xwiki.script.service.ScriptService; +import org.xwiki.stability.Unstable; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.XWikiException; +import com.xpn.xwiki.api.User; +import com.xpn.xwiki.doc.XWikiDocument; +import com.xwiki.azureoauth.configuration.EntraIDConfiguration; + +import static com.xwiki.azureoauth.internal.configuration.DefaultEntraIDConfiguration.OIDC_USER_CLASS; + +/** + * Entra ID script services. + * + * @version $Id$ + * @since 2.0 + */ +@Component +@Named("entraid") +@Singleton +@Unstable +public class EntraIDScriptService implements ScriptService +{ + @Inject + private Provider wikiContextProvider; + + @Inject + @Named("default") + private EntraIDConfiguration entraIDConfiguration; + + @Inject + @Named("current") + private DocumentReferenceResolver documentReferenceResolver; + + /** + * Check if XWiki log in is enabled for guest users. + * + * @return {@code true} if global log in is enabled and {@code false} otherwise. + */ + public boolean isXWikiLoginEnabled() + { + return entraIDConfiguration.isXWikiLoginGlobalEnabled(); + } + + /** + * Check if the XWiki log in switch option should be displayed. + * + * @return {@code true} if the user is an Azure user and member of the allowed groups and {@code false} otherwise. + * @throws XWikiException + */ + public boolean shouldDisplayXWikiLogin() throws XWikiException + { + return isAzureUser() && isUserInGroups(); + } + + private boolean isAzureUser() throws XWikiException + { + XWikiContext wikiContext = wikiContextProvider.get(); + XWiki xwiki = wikiContext.getWiki(); + XWikiDocument userDoc = xwiki.getDocument(wikiContext.getUserReference(), wikiContext); + return userDoc.getXObject(documentReferenceResolver.resolve(OIDC_USER_CLASS)) != null; + } + + private boolean isUserInGroups() + { + XWikiContext wikiContext = wikiContextProvider.get(); + XWiki xwiki = wikiContext.getWiki(); + User user = xwiki.getUser(wikiContext.getUserReference(), wikiContext); + return Stream.of(entraIDConfiguration.getXWikiLoginGroups().split(",")).anyMatch(user::isUserInGroup); + } +} diff --git a/api/src/main/resources/META-INF/components.txt b/api/src/main/resources/META-INF/components.txt index 409801d..a8e97b1 100644 --- a/api/src/main/resources/META-INF/components.txt +++ b/api/src/main/resources/META-INF/components.txt @@ -1,5 +1,3 @@ -com.xwiki.azureoauth.AzureADIdentityOAuthProvider -com.xwiki.azureoauth.AzureADOAuthClient com.xwiki.azureoauth.internal.AzureADOIDCMigrator com.xwiki.azureoauth.internal.EntraIDObjectUpdateListener com.xwiki.azureoauth.internal.configuration.DefaultEntraIDConfiguration @@ -8,3 +6,5 @@ com.xwiki.azureoauth.internal.configuration.EntraIDConfigurationSource com.xwiki.azureoauth.internal.oldConfiguration.OldAzureOAuthConfiguration com.xwiki.azureoauth.internal.oldConfiguration.OldAzureConfigurationSource com.xwiki.azureoauth.internal.oldConfiguration.OldIdentityOAuthConfigurationSource +com.xwiki.azureoauth.internal.rest.DefaultEntraIDResource +com.xwiki.azureoauth.script.EntraIDScriptService diff --git a/api/src/test/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResourceTest.java b/api/src/test/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResourceTest.java new file mode 100644 index 0000000..ce5b889 --- /dev/null +++ b/api/src/test/java/com/xwiki/azureoauth/internal/rest/DefaultEntraIDResourceTest.java @@ -0,0 +1,87 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.azureoauth.internal.rest; + +import javax.inject.Provider; +import javax.ws.rs.WebApplicationException; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.xwiki.rest.XWikiRestException; +import org.xwiki.test.LogLevel; +import org.xwiki.test.junit5.LogCaptureExtension; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ComponentTest +class DefaultEntraIDResourceTest +{ + @InjectMockComponents + private DefaultEntraIDResource defaultEntraIDResource; + + @MockComponent + private Provider wikiContextProvider; + + @MockComponent + private XWikiContext wikiContext; + + @RegisterExtension + private LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.WARN); + + @Mock + private XWiki wiki; + + @Test + void xwikiLoginTest() throws XWikiRestException + { + when(wikiContextProvider.get()).thenReturn(wikiContext); + when(wikiContext.getWiki()).thenReturn(wiki); + String redirectDocumentURL = "http://localhost:8080/xwiki/bin/view/Sandbox/WebHome"; + when(wiki.getURL("Sandbox.WebHome", "view", "", wikiContext)).thenReturn(redirectDocumentURL); + String parameters = String.format("xredirect=%s&loginLink=1&oidc.skipped=true", redirectDocumentURL); + when(wiki.getURL("XWiki.XWikiLogin", "login", parameters, wikiContext)).thenReturn("login_url"); + assertEquals(303, defaultEntraIDResource.xwikiLogin("Sandbox.WebHome").getStatus()); + } + + @Test + void xwikiLoginTestFail() throws XWikiRestException + { + when(wikiContextProvider.get()).thenReturn(wikiContext); + when(wikiContext.getWiki()).thenReturn(wiki); + String redirectDocumentURL = null; + when(wiki.getURL("Sandbox.WebHome", "view", "", wikiContext)).thenReturn(redirectDocumentURL); + String parameters = String.format("xredirect=%s&loginLink=1&oidc.skipped=true", redirectDocumentURL); + when(wiki.getURL("XWiki.XWikiLogin", "login", parameters, wikiContext)).thenReturn(null); + WebApplicationException exception = assertThrows(WebApplicationException.class, () -> { + defaultEntraIDResource.xwikiLogin("Sandbox.WebHome"); + }); + assertEquals("Failed to generate the log in redirect URL. Root cause: [NullPointerException: ]", logCapture.getMessage(0)); + assertEquals(500, exception.getResponse().getStatus()); + } +} diff --git a/pom.xml b/pom.xml index d3f17f6..bc11f3b 100644 --- a/pom.xml +++ b/pom.xml @@ -30,12 +30,11 @@ 1.9.1-SNAPSHOT pom - Microsoft Azure Active Directory Single-Sign-On (SSO) (pro) parent POM - This extension allows users to authenticate to the wiki using Azure Active Directory. The app can be purchased individually or part of the XWiki Pro package. Try it free. + Microsoft Entra ID SSO parent POM + This extension allows users to authenticate to the wiki using Entra ID, formerly known as Azure Active Directory. The app can be purchased individually or part of the XWiki Pro package. Try it free. 1.25 - 1.9 14.10 true @@ -71,7 +70,6 @@ api - admin-ui ui diff --git a/ui/pom.xml b/ui/pom.xml index 1ef310a..d9cffdc 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -28,20 +28,20 @@ integration-azure-oauth-ui xar - Microsoft Azure Active Directory Single-Sign-On (SSO) (pro) - This extension allows users to authenticate to the wiki using Azure Active Directory. The app can be purchased individually or part of the XWiki Pro package. Try it free. + Microsoft Entra ID SSO + This extension allows users to authenticate to the wiki using Entra ID, formerly known as Azure Active Directory. The app can be purchased individually or part of the XWiki Pro package. Try it free. - AzureAD.WebHome + EntraID.WebHome - AzureAD.AzureADConfig + EntraID.Code.EntraOIDCClientConfiguration - Microsoft Azure Active Directory Single Sign-On (SSO) (Pro) + Microsoft Entra ID OpenID Connect (OIDC) true true @@ -51,14 +51,21 @@ com.xwiki.integration-azure-oauth - integration-azure-oauth-admin-ui + integration-azure-oauth-api ${project.version} - xar + jar com.xwiki.licensing application-licensing-licensor-api ${licensing.version} + + org.xwiki.contrib + authservice-backport-ui + 1.1.1 + true + xar + diff --git a/ui/src/main/resources/AzureAD/AzureADConfigSheet.xml b/ui/src/main/resources/AzureAD/AzureADConfigSheet.xml deleted file mode 100644 index 1d36564..0000000 --- a/ui/src/main/resources/AzureAD/AzureADConfigSheet.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - AzureAD - AzureADConfigSheet - - - 0 - xwiki:XWiki.Admin - AzureAD.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - AzureAD Configuration Sheet - - false - xwiki/2.1 - true - {{velocity output=false}} - #set($configDocName="AzureAD.AzureADConfig") - #set($providerHint = "AzureAD") - #set($productPage = "https://store.xwiki.com/xwiki/bin/view/Extension/MicrosoftAzureSSO/") - #set($extraObjectClassPropPrefixes = [["AzureADAdmin.AzureADConfigClass","tenantid"]]) - #set($translationPrefix = "azureADAdmin.AzureADConfigClass_") - {{/velocity}} - - {{include reference="AzureADAdmin.AzureADConfigSheet" /}} - - diff --git a/ui/src/main/resources/AzureAD/AzureADOAuthProvider.xml b/ui/src/main/resources/AzureAD/AzureADOAuthProvider.xml deleted file mode 100644 index f81f1da..0000000 --- a/ui/src/main/resources/AzureAD/AzureADOAuthProvider.xml +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - AzureAD - AzureADOAuthProvider - - - 0 - xwiki:XWiki.Admin - AzureAD.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - - <comment/> - <minorEdit>false</minorEdit> - <syntaxId>xwiki/2.1</syntaxId> - <hidden>true</hidden> - <content/> - <object> - <name>AzureAD.AzureADOAuthProvider</name> - <number>0</number> - <className>IdentityOAuth.OAuthProviderClass</className> - <guid>8d75c3b4-6dc7-4090-9e94-286ab71b1a79</guid> - <class> - <name>IdentityOAuth.OAuthProviderClass</name> - <customClass/> - <customMapping/> - <defaultViewSheet/> - <defaultEditSheet/> - <defaultWeb/> - <nameField/> - <validationScript/> - <active> - <customDisplay/> - <defaultValue/> - <disabled>0</disabled> - <displayFormType>checkbox</displayFormType> - <displayType/> - <hint/> - <name>active</name> - <number>9</number> - <prettyName>active</prettyName> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.BooleanClass</classType> - </active> - <configurationObjectsPage> - <cache>0</cache> - <classname/> - <customDisplay/> - <defaultValue/> - <disabled>0</disabled> - <displayType>input</displayType> - <freeText/> - <hint/> - <idField/> - <largeStorage>0</largeStorage> - <multiSelect>0</multiSelect> - <name>configurationObjectsPage</name> - <number>4</number> - <picker>1</picker> - <prettyName>configurationObjectsPage</prettyName> - <relationalStorage>0</relationalStorage> - <separator> </separator> - <separators/> - <size>1</size> - <sort/> - <sql/> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <valueField/> - <classType>com.xpn.xwiki.objects.classes.PageClass</classType> - </configurationObjectsPage> - <loginTemplate> - <contenttype>---</contenttype> - <customDisplay/> - <disabled>0</disabled> - <editor>---</editor> - <hint/> - <name>loginTemplate</name> - <number>2</number> - <picker>1</picker> - <prettyName>loginTemplate</prettyName> - <rows>5</rows> - <size>40</size> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType> - </loginTemplate> - <orderHint> - <customDisplay/> - <disabled>0</disabled> - <hint/> - <name>orderHint</name> - <number>4</number> - <numberType>long</numberType> - <prettyName>orderHint</prettyName> - <size>30</size> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.NumberClass</classType> - </orderHint> - <providerHint> - <customDisplay/> - <disabled>0</disabled> - <hint/> - <name>providerHint</name> - <number>1</number> - <picker>1</picker> - <prettyName>providerHint</prettyName> - <size>30</size> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.StringClass</classType> - </providerHint> - </class> - <property> - <active>1</active> - </property> - <property> - <configurationObjectsPage>xwiki:AzureAD.AzureADConfig</configurationObjectsPage> - </property> - <property> - <loginTemplate>{{velocity}} -{{html clean=false}} -<a href="-URL-&provider=-PROVIDER-" class="btn provider-login-button"><img alt="Logo Microsoft" - src="--image-base64--AzureAD.WebHome@AzureAD-logo.svg--"> - $escapetool.xml($services.localization.render("azureADAdmin.loginWithAzureAD")) -</a> -{{/html}} -{{/velocity}}</loginTemplate> - </property> - <property> - <orderHint>10</orderHint> - </property> - <property> - <providerHint>AzureAD</providerHint> - </property> - </object> -</xwikidoc> diff --git a/ui/src/main/resources/AzureAD/Install.xml b/ui/src/main/resources/AzureAD/Install.xml deleted file mode 100644 index c9b5bbe..0000000 --- a/ui/src/main/resources/AzureAD/Install.xml +++ /dev/null @@ -1,69 +0,0 @@ -<?xml version="1.1" encoding="UTF-8"?> - -<!-- - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. ---> - -<xwikidoc version="1.5" reference="AzureAD.Install" locale=""> - <web>AzureAD</web> - <name>Install</name> - <language/> - <defaultLanguage/> - <translation>0</translation> - <creator>xwiki:XWiki.Admin</creator> - <parent>AzureAD.WebHome</parent> - <author>xwiki:XWiki.Admin</author> - <contentAuthor>xwiki:XWiki.Admin</contentAuthor> - <version>1.1</version> - <title>AzureAD Installation - - false - xwiki/2.0 - true - {{velocity}} -#if(!$xwiki.hasAdminRights()) - You are running this script as a non admin. It will have no effect. Login as admin. -#else - This script automatically set the owner of the pages in the Identity OAuth Application. This will allow the priviledged scripts included in them to work. -#end -#if($request.confirm=="1") - Assigning programming rights to the following pages: -#else - [[Confirm assigning programming rights to the following pages:>>$doc.fullName?confirm=1]] -#end - -#foreach($item in $xwiki.searchDocuments("where doc.web='AzureAD'")) -* $item #if($request.confirm=="1") $xwiki.getDocument($item).save() #end - -#end - -#set($transdoc = $xwiki.getDocument("XWiki.XWikiPreferences")) -#set($ok = $transdoc.setTitle($transdoc.getTitle())) -#set($ok = $transdoc.use("XWiki.XWikiPreferences")) -#set($transprefs = $transdoc.getValue("documentBundles")) -#if($transprefs.indexOf("AzureAD.Translations")==-1) - #if($request.confirm=="1") - #set($transprefs = "${transprefs},AzureAD.Translations") - #set($ok = $transdoc.set("documentBundles", $transprefs)) - #set($ok = $transdoc.save()) - #end -* Added translation bundle to XWiki Preferences -#end -{{/velocity}} - diff --git a/ui/src/main/resources/AzureAD/OAuthLogout.xml b/ui/src/main/resources/AzureAD/OAuthLogout.xml deleted file mode 100644 index 39f4601..0000000 --- a/ui/src/main/resources/AzureAD/OAuthLogout.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - AzureAD - OAuthLogout - - - 0 - xwiki:XWiki.Admin - xwiki:Main.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - OAuth Logout - - false - xwiki/2.1 - true - - = OAuth Logout = - Cleaning your session of AzureAD information... - - {{velocity}} - $services.identityoauth.clearAllSessionInfos() - $response.sendRedirect($xwiki.getDocument("XWiki.XWikiLogout").getURL("logout")) - {{/velocity}} - - diff --git a/ui/src/main/resources/AzureAD/WebHome.xml b/ui/src/main/resources/AzureAD/WebHome.xml deleted file mode 100644 index 46051dd..0000000 --- a/ui/src/main/resources/AzureAD/WebHome.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - AzureAD - WebHome - - - 0 - xwiki:XWiki.Admin - xwiki:Main.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - Microsoft Azure Active Directory Single Sign-On (SSO) - - false - xwiki/2.1 - true - {{velocity}} -#set ($reference = $services.model.createDocumentReference("xwiki", ["AzureAD"], "WebPreferences")) -#if (!$services.licensing.licensor.hasLicensureForEntity($references)) - {{missingLicenseMessage extensionName="azureAD.extension.name"/}} -#else -This space contains the code for the Azure Active Directory Integration of XWiki. - This extensions currently allows users to login with XWiki by authorizing the transmission - of profile information from an Azure Active Directory node. It uses the OAuth protocol - and, thus, the OpenID basic derivative. - -For the application to work, it needs to be activated and configured. - The configuration requires an app to be registered and authorized within the Azure - configuration. This process yields a client-id, a secret, and a tenant-id - that are input in the Wiki's configuration. - The detailed installation instructions are at the [[extensions' page>>]]. -#end -{{/velocity}} - - AzureAD-logo.svg - image/svg+xml - xwiki:XWiki.Admin - 1.1 - - PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMyAyMyI+PHBhdGggZmlsbD0iI2YzZjNmMyIgZD0iTTAgMGgyM3YyM0gweiIvPjxwYXRoIGZpbGw9IiNmMzUzMjUiIGQ9Ik0xIDFoMTB2MTBIMXoiLz48cGF0aCBmaWxsPSIjODFiYzA2IiBkPSJNMTIgMWgxMHYxMEgxMnoiLz48cGF0aCBmaWxsPSIjMDVhNmYwIiBkPSJNMSAxMmgxMHYxMEgxeiIvPjxwYXRoIGZpbGw9IiNmZmJhMDgiIGQ9Ik0xMiAxMmgxMHYxMEgxMnoiLz48L3N2Zz4= - 272 - - diff --git a/ui/src/main/resources/AzureAD/WebPreferences.xml b/ui/src/main/resources/AzureAD/WebPreferences.xml deleted file mode 100644 index 7228a26..0000000 --- a/ui/src/main/resources/AzureAD/WebPreferences.xml +++ /dev/null @@ -1,1651 +0,0 @@ - - - - - - AzureAD - WebPreferences - - - 0 - xwiki:XWiki.Admin - AzureAD.WebHome - xwiki:XWiki.Admin - xwiki:XWiki.Admin - 1.1 - $services.localization.render('admin.preferences.title') - - false - xwiki/2.1 - true - - - AzureAD.WebPreferences - 0 - XWiki.XWikiGlobalRights - e21fe1bd-c11b-4c12-b8cb-faf05a6840a2 - - XWiki.XWikiGlobalRights - - - - - - - - - 1 - 0 - select - allow - allow - 4 - Allow/Deny - 0 - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - 0 - input - 1 - groups - 1 - 1 - Groups - 0 - - 5 - 0 - com.xpn.xwiki.objects.classes.GroupsClass - - - 0 - 0 - select - 1 - levels - 2 - Levels - 0 - - 3 - 0 - com.xpn.xwiki.objects.classes.LevelsClass - - - 0 - 0 - input - 1 - users - 3 - 1 - Users - 0 - - 5 - 0 - com.xpn.xwiki.objects.classes.UsersClass - - - - 1 - - - XWiki.XWikiAllGroup - - - view - - - - - - - AzureAD.WebPreferences - 1 - XWiki.XWikiGlobalRights - 6072cfa9-d6fb-4314-872e-240ba6b8ecd7 - - XWiki.XWikiGlobalRights - - - - - - - - - 1 - 0 - select - allow - allow - 4 - Allow/Deny - 0 - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - 0 - input - 1 - groups - 1 - 1 - Groups - 0 - - 5 - 0 - com.xpn.xwiki.objects.classes.GroupsClass - - - 0 - 0 - select - 1 - levels - 2 - Levels - 0 - - 3 - 0 - com.xpn.xwiki.objects.classes.LevelsClass - - - 0 - 0 - input - 1 - users - 3 - 1 - Users - 0 - - 5 - 0 - com.xpn.xwiki.objects.classes.UsersClass - - - - 1 - - - - - - view - - - XWiki.XWikiGuest - - - - AzureAD.WebPreferences - 0 - XWiki.XWikiPreferences - a50f0c94-db90-44e4-8319-05dcd5b85355 - - XWiki.XWikiPreferences - - internal - - - - - - - - 0 - 0 - select - yesno - accessibility - 11 - Enable extra accessibility features - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - admin_email - 19 - 0 - Admin eMail - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - authenticate_edit - 4 - Authenticated Edit - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - authenticate_view - 5 - Authenticated View - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - backlinks - 40 - Activate the backlinks - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - - {{include reference="XWiki.ColorThemePropertyDisplayer" /}} - 0 - select - - 0 - colorTheme - 7 - 0 - Color theme - 0 - - - 1 - none - select doc.fullName, doc.title from XWikiDocument as doc, BaseObject as theme where doc.fullName=theme.name and (theme.className='ColorThemes.ColorThemeClass' or theme.className='FlamingoThemesCode.ThemeClass') and doc.fullName<>'ColorThemes.ColorThemeTemplate' and doc.fullName<>'FlamingoThemesCode.ThemeTemplate' - 0 - - - - com.xpn.xwiki.objects.classes.DBListClass - - - 0 - - 0 - select - forbidden - 0 - 0 - comment_anonymous - 33 - 1 - Anonymous - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - 0 - - 0 - select - forbidden - 0 - 0 - comment_registered - 34 - 1 - Registered - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - PureText - - 0 - PureText - confirmation_email_content - 26 - 0 - Confirmation eMail Content - 0 - 10 - 72 - - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - {{velocity}} -{{html wiki="false" clean="false"}} -#if ("$!value" == '') - #set ($value = $xwiki.getDefaultDocumentSyntax()) -#end -<select name="${object.getxWikiClass().name}_${object.number}_${name}" id="${object.getxWikiClass().name}_${object.number}_${name}"> -#set ($configuredSyntaxes = $collectiontool.sort($services.rendering.getConfiguredSyntaxes())) -#foreach($syntax in $configuredSyntaxes) - <option value="$syntax.toIdString()"#if($syntax.toIdString().equalsIgnoreCase($value)) selected="selected"#end>$syntax.toString()</option> -#end -</select> -{{/html}} -{{/velocity}} - 0 - core.defaultDocumentSyntax - 37 - 0 - Default document syntax - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - dateformat - 17 - 0 - Date Format - 30 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - default_language - 3 - 0 - Default Language - 5 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - - - 0 - input - discouraged - - - 0 - documentBundles - 48 - 1 - Internationalization Document Bundles - 0 - - - 60 - none - - 0 - - - - com.xpn.xwiki.objects.classes.PageClass - - - 0 - - 0 - select - forbidden - 0 - 0 - edit_anonymous - 31 - 1 - Anonymous - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - 0 - - 0 - select - forbidden - 0 - 0 - edit_registered - 32 - 1 - Registered - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - - - 0 - select - yesno - editcomment - 74 - Enable version summary - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - editcomment_mandatory - 75 - Make version summary mandatory - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - - 0 - select - forbidden - 0 - 0 - editor - 12 - 1 - Default Editor - 0 - - |, - 1 - none - - 0 - - - Text|Wysiwyg - com.xpn.xwiki.objects.classes.StaticListClass - - - - - 0 - select - select - guest_comment_requires_captcha - 36 - Enable CAPTCHA in comments for unregistered users - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - 0 - select - 0 - iconTheme - 8 - Icon theme - 0 - - 1 - select doc.fullName, propName.value from XWikiDocument as doc, BaseObject as theme, StringProperty propName where doc.fullName=theme.name and theme.className='IconThemesCode.IconThemeClass' and doc.fullName<>'IconThemesCode.IconThemeTemplate' and theme.id = propName.id and propName.name = 'name' - 0 - com.xpn.xwiki.objects.classes.DBListClass - - - PureText - - 0 - PureText - invitation_email_content - 27 - 0 - Invitation eMail Content - 0 - 10 - 72 - - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - PureText - - 0 - PureText - javamail_extra_props - 24 - 0 - Additional JavaMail properties - 0 - 6 - 60 - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - - 0 - languages - 47 - 0 - Supported languages - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - ldap - 50 - Ldap - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - ldap_UID_attr - 59 - 0 - Ldap UID attribute name - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - ldap_base_DN - 58 - 0 - Ldap base DN - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - ldap_bind_DN - 53 - 0 - Ldap login matching - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - ldap_bind_pass - 54 - Ldap password matching - 60 - Clear - 0 - com.xpn.xwiki.objects.classes.PasswordClass - - - - 0 - ldap_exclude_group - 57 - 0 - Ldap group to exclude - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - PureText - - 0 - PureText - ldap_fields_mapping - 60 - 0 - Ldap user fields mapping - 0 - 1 - 60 - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - PureText - - 0 - PureText - ldap_group_mapping - 65 - 0 - Ldap groups mapping - 0 - 5 - 60 - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - - 0 - ldap_groupcache_expiration - 66 - 0 - LDAP groups members cache - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - - 0 - select - forbidden - 0 - 0 - ldap_mode_group_sync - 67 - 0 - LDAP groups sync mode - 0 - - |, - 1 - none - 0 - - - always|create - com.xpn.xwiki.objects.classes.StaticListClass - - - - 0 - ldap_photo_attachment_name - 63 - 0 - Attachment name to save LDAP photo - 30 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - ldap_photo_attribute - 64 - 0 - Ldap photo attribute name - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - ldap_port - 52 - 0 - Ldap server port - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - ldap_server - 51 - 0 - Ldap server adress - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - ldap_trylocal - 68 - Try local login - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - ldap_update_photo - 62 - Update user photo from LDAP - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - ldap_update_user - 61 - Update user from LDAP - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - ldap_user_group - 56 - 0 - Ldap group filter - 60 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - ldap_validate_password - 55 - Validate Ldap user/password - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - leftPanels - 41 - 0 - Panels displayed on the left - 60 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - 0 - select - forbidden - 0 - 0 - leftPanelsWidth - 45 - Width of the left panel column - 0 - - |, - 1 - 0 - Small|Medium|Large - com.xpn.xwiki.objects.classes.StaticListClass - - - PureText - - 0 - PureText - meta - 16 - 0 - HTTP Meta Info - 0 - 8 - 60 - - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - - - 0 - select - yesno - minoredit - 76 - Enable minor edits - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - multilingual - 2 - Multi-Lingual - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - 0 - select - yesno - obfuscateEmailAddresses - 28 - Obfuscate Email Addresses - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - 0 - parent - 1 - 0 - Parent Space - 30 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - plugins - 4 - 0 - Plugins - 40 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - - 0 - select - forbidden - 0 - 0 - registration_anonymous - 29 - 1 - Anonymous - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - 0 - - 0 - select - forbidden - 0 - 0 - registration_registered - 30 - 1 - Registered - 0 - - |, - 1 - none - - 0 - - - Image|Text - com.xpn.xwiki.objects.classes.StaticListClass - - - - 0 - rightPanels - 42 - 0 - Panels displayed on the right - 60 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - 0 - 0 - select - forbidden - 0 - 0 - rightPanelsWidth - 46 - Width of the right panel column - 0 - - |, - 1 - 0 - Small|Medium|Large - com.xpn.xwiki.objects.classes.StaticListClass - - - - - 0 - select - yesno - showLeftPanels - 43 - Display the left panel column - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showRightPanels - 44 - Display the right panel column - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showannotations - 69 - Show document annotations - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showattachments - 71 - Show document attachments - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showcomments - 70 - Show document comments - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showhistory - 72 - Show document history - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - 0 - select - yesno - showinformation - 73 - Show document information - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - - - 0 - input - allowed - - - 0 - skin - 6 - 1 - Skin - 0 - - - 30 - none - , BaseObject obj where doc.fullName = obj.name and obj.className = 'XWiki.XWikiSkins' - 0 - - - - com.xpn.xwiki.objects.classes.PageClass - - - - 0 - smtp_port - 21 - 0 - SMTP Port - 5 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - smtp_server - 20 - 0 - SMTP Server - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - smtp_server_password - 23 - 0 - Server password (optional) - 30 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - smtp_server_username - 22 - 0 - Server username (optional) - 30 - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - stylesheet - 9 - 0 - Default Stylesheet - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - stylesheets - 10 - 0 - Alternative Stylesheet - 60 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - tags - 39 - Activate the tagging - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - 0 - timezone - 49 - Time Zone - 30 - 0 - com.xpn.xwiki.objects.classes.TimezoneClass - - - <customDisplay/> - <disabled>0</disabled> - <name>title</name> - <number>14</number> - <picker>0</picker> - <prettyName>Title</prettyName> - <size>30</size> - <tooltip/> - <unmodifiable>0</unmodifiable> - <validationMessage/> - <validationRegExp/> - <classType>com.xpn.xwiki.objects.classes.StringClass</classType> - - - - 0 - upload_maxsize - 35 - long - Maximum Upload Size - 5 - 0 - - - com.xpn.xwiki.objects.classes.NumberClass - - - - - 0 - select - yesno - use_email_verification - 18 - Use eMail Verification - - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - PureText - - 0 - PureText - validation_email_content - 25 - 0 - Validation eMail Content - 0 - 10 - 72 - - 0 - - - com.xpn.xwiki.objects.classes.TextAreaClass - - - - 0 - version - 15 - 0 - Version - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - 0 - webcopyright - 13 - 0 - Copyright - 30 - - 0 - - - com.xpn.xwiki.objects.classes.StringClass - - - - - 0 - select - yesno - xwiki.title.mandatory - 38 - Make document title field mandatory - 0 - - - com.xpn.xwiki.objects.classes.BooleanClass - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - </property> - <property> - <upload_maxsize/> - </property> - <property> - <validation_email_content/> - </property> - <property> - <version/> - </property> - <property> - <webcopyright/> - </property> - <property> - <xwiki.title.mandatory/> - </property> - </object> -</xwikidoc> diff --git a/ui/src/main/resources/EntraID/Code/EntraOIDCClientConfiguration.xml b/ui/src/main/resources/EntraID/Code/EntraOIDCClientConfiguration.xml index f305206..ce11000 100644 --- a/ui/src/main/resources/EntraID/Code/EntraOIDCClientConfiguration.xml +++ b/ui/src/main/resources/EntraID/Code/EntraOIDCClientConfiguration.xml @@ -323,7 +323,7 @@ <categoryIcon/> </property> <property> - <codeToExecute/> + <codeToExecute>{{include reference="EntraID.Code.EntraOIDCClientConfigurationSheet" /}}</codeToExecute> </property> <property> <configurationClass/> diff --git a/admin-ui/src/main/resources/AzureADAdmin/Translations.xml b/ui/src/main/resources/EntraID/Code/Translations.xml similarity index 70% rename from admin-ui/src/main/resources/AzureADAdmin/Translations.xml rename to ui/src/main/resources/EntraID/Code/Translations.xml index d6b182c..b2c3811 100644 --- a/admin-ui/src/main/resources/AzureADAdmin/Translations.xml +++ b/ui/src/main/resources/EntraID/Code/Translations.xml @@ -20,14 +20,14 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> -<xwikidoc version="1.5" reference="AzureADAdmin.Translations" locale=""> - <web>AzureADAdmin</web> +<xwikidoc version="1.5" reference="EntraID.Code.Translations" locale=""> + <web>EntraID.Code</web> <name>Translations</name> <language/> <defaultLanguage>en</defaultLanguage> <translation>0</translation> <creator>xwiki:XWiki.Admin</creator> - <parent>AzureADAdmin.WebHome</parent> + <parent>WebHome</parent> <author>xwiki:XWiki.Admin</author> <contentAuthor>xwiki:XWiki.Admin</contentAuthor> <version>1.1</version> @@ -36,35 +36,11 @@ <minorEdit>false</minorEdit> <syntaxId>plain/1.0</syntaxId> <hidden>true</hidden> - <content>admin.azureAD=Azure AD -# Login page -azureADAdmin.loginWithAzureAD = Login with Azure Active Directory - -# Admin (extras compared to IdentityOAuth/Translations -azureADAdmin.config.heading=AzureAD Integration Configuration -azureADAdmin.AzureADConfigClass_config.explanation=XWiki can be integrated to login XWiki users with Azure Active Directory -azureAD.extension.name=Microsoft Azure Active Directory Single Sign-On (SSO) (Pro) - -azureADAdmin.AzureADConfigClass_communicate=Communication with the Azure Active Directory services -azureADAdmin.AzureADConfigClass_communicate.hint=To activate the Azure AD integration you need to {0} and to insert your client-Id, tenant-id and secret in the following settings. -azureADAdmin.AzureADConfigClass_communicate.hint.linkLabel=register for OAuth access on the Microsoft Azure console -azureADAdmin.AzureADConfigClass_communicate.hint2=For more information, please see {0}. -azureADAdmin.AzureADConfigClass_communicate.hint2.linkLabel=the installation instructions - -azureADAdmin.AzureADConfigClass_tenantid=Tenant ID -azureADAdmin.AzureADConfigClass_tenantid.hint=As provided in the Azure overview. - - -azureADAdmin.AzureADConfigClass_nowWhat1=Once this is configured please log out and login by clicking "Login with Azure AD". -azureADAdmin.AzureADConfigClass_nowWhat2=Should you have technical difficulties, please write to support@xwikisas.com . - -## a single change for avatar's setting -azureADAdmin.AzureADConfigClass_scope_avatar.onlyOutlook = only works with Outlook-enabled-accounts, a {0} limitation -azureADAdmin.AzureADConfigClass_scope_avatar.onlyOutlook.linkLabel=known - -## New configuration + <content>## New configuration +entraID.extension.name=Microsoft Entra ID OpenID Connect (OIDC) +entraID.extension.home.description=This space contains the code for the Entra ID OpenID Connect Integration of XWiki. This extensions currently allows users to login with XWiki by authorizing the transmission of profile information from an Microsoft Entra ID node. It uses the OIDC protocol. XWiki.OIDC.ClientConfigurationClass_enableUser=Enable user profiles on first login -XWiki.OIDC.ClientConfigurationClass_skipped=Disable Azure authentication +XWiki.OIDC.ClientConfigurationClass_skipped=Disable Entra ID authentication XWiki.OIDC.ClientConfigurationClass_userInfoSkip=Use user info endpoint XWiki.OIDC.ClientConfigurationClass_scope=Scope XWiki.OIDC.ClientConfigurationClass_groupsClaim=Groups claim @@ -80,18 +56,18 @@ EntraID.Code.EntraIDConfigurationClass_enableXWikiLoginGlobal=Allow XWiki Login EntraID.Code.EntraIDConfigurationClass_xwikiLoginGroups=XWiki login user groups XWiki.OIDC.ClientConfigurationClass_enableUser.hint=Define if user accounts should be enabled (marked as active) on first login. -XWiki.OIDC.ClientConfigurationClass_skipped.hint=Disable the Azure AD authentication. +XWiki.OIDC.ClientConfigurationClass_skipped.hint=Disable the Entra ID authentication. XWiki.OIDC.ClientConfigurationClass_userInfoSkip.hint=Some providers have a bad implementation of the userinfo endpoint, making it unusable. XWiki.OIDC.ClientConfigurationClass_scope.hint=The scopes to use when redirecting to the provider. XWiki.OIDC.ClientConfigurationClass_groupsClaim.hint=Indicate the field containing the list of groups (in case it's not an OpenID Connect standard). -XWiki.OIDC.ClientConfigurationClass_groupsMapping.hint=Associates the XWiki groups with Azure AD groups. +XWiki.OIDC.ClientConfigurationClass_groupsMapping.hint=Associates the XWiki groups with Entra ID groups. XWiki.OIDC.ClientConfigurationClass_allowedGroups.hint=The groups the user need to belong to be allowed to authenticate. XWiki.OIDC.ClientConfigurationClass_forbiddenGroups.hint=The groups that if a user belongs to, it will not be allowed to authenticate. XWiki.OIDC.ClientConfigurationClass_userNameFormatter.hint=The pattern to use to generate the unique identifier of the user. XWiki.OIDC.ClientConfigurationClass_userMapping.hint=Associate non-standard properties coming from the OpenID Connect provider with the XWiki user. XWiki.OIDC.ClientConfigurationClass_clientSecret.hint=The client secret registered on the provider. XWiki.OIDC.ClientConfigurationClass_clientId.hint=The client identifier used by the authentication. -EntraID.Code.EntraIDConfigurationClass_tenantId.hint=Azure AD instance ID. +EntraID.Code.EntraIDConfigurationClass_tenantId.hint=Entra ID instance ID. EntraID.Code.EntraIDConfigurationClass_enableXWikiLoginGlobal.hint=Allow a guest user to login using the standard XWiki authenticator. EntraID.Code.EntraIDConfigurationClass_xwikiLoginGroups.hint=User groups allowed to log in with XWiki. @@ -101,9 +77,12 @@ entra.properties.data.tip.value.groupMap=Group object ID... entra.properties.data.tip.key.userMap=XWiki user property... entra.properties.data.tip.value.userMap=Provider property... entra.properties.data.tip.value.forbiddenGroup=Forbidden groups... -entra.properties.data.tip.value.allowedGroup=Allowed groups...</content> +entra.properties.data.tip.value.allowedGroup=Allowed groups... + +entra.drawer.header.login=Log in with XWiki +entra.drawer.header.switch=Switch to XWiki user</content> <object> - <name>AzureADAdmin.Translations</name> + <name>EntraID.Code.Translations</name> <number>0</number> <className>XWiki.TranslationDocumentClass</className> <guid>01d84622-baf7-448b-96a4-93fcd4276764</guid> diff --git a/ui/src/main/resources/EntraID/WebHome.xml b/ui/src/main/resources/EntraID/WebHome.xml new file mode 100644 index 0000000..65d78c8 --- /dev/null +++ b/ui/src/main/resources/EntraID/WebHome.xml @@ -0,0 +1,315 @@ +<?xml version="1.1" encoding="UTF-8"?> + +<!-- + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. +--> + +<xwikidoc version="1.5" reference="EntraID.WebHome" locale=""> + <web>EntraID</web> + <name>WebHome</name> + <language/> + <defaultLanguage/> + <translation>0</translation> + <creator>xwiki:XWiki.Admin</creator> + <parent>xwiki:Main.WebHome</parent> + <author>xwiki:XWiki.Admin</author> + <contentAuthor>xwiki:XWiki.Admin</contentAuthor> + <version>1.1</version> + <title>Microsoft Entra ID OpenID Connect (OIDC) + + false + xwiki/2.1 + true + {{velocity}} +#set ($reference = $services.model.createDocumentReference('xwiki', ['EntraID'], 'WebPreferences')) +#if (!$services.licensing.licensor.hasLicensureForEntity($references)) + {{missingLicenseMessage extensionName='entraID.extension.name'/}} +#else + $escapetool.xml($services.localization.render('entraID.extension.home.description')) +#end +{{/velocity}} + + EntraID.WebHome + 0 + XWiki.JavaScriptExtension + 439d079c-907d-44f7-8e6d-55ed3524a765 + + XWiki.JavaScriptExtension + + + + + + + + + 0 + long + 0 + select + forbidden + 0 + 0 + cache + 5 + Caching policy + 0 + + |, + 1 + 0 + long|short|default|forbid + com.xpn.xwiki.objects.classes.StaticListClass + + + PureText + 0 + PureText + code + 2 + Code + 0 + 20 + 50 + 0 + com.xpn.xwiki.objects.classes.TextAreaClass + + + 0 + name + 1 + Name + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + select + yesno + parse + 4 + Parse content + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + 0 + select + forbidden + 0 + 0 + use + 3 + Use this extension + 0 + + |, + 1 + 0 + currentPage|onDemand|always + com.xpn.xwiki.objects.classes.StaticListClass + + + + long + + + require(['jquery'], function($) { + $(document).on('click', '#tmLogin', function(event) { + event.preventDefault(); + console.log('click login') + document.cookie = "oidcProvider=Entra ID; path=/"; + window.location.href = event.currentTarget.href; + }); +}) + + + + + + + + + + onDemand + + + + EntraID.WebHome + 0 + XWiki.UIExtensionClass + 8963ba00-2dfe-4084-9371-78307ea76911 + + XWiki.UIExtensionClass + + + + + + + + + 0 + 0 + select + + async_cached + 3 + Cached + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + 0 + select + forbidden + 0 + 1 + async_context + 4 + Context elements + 0 + , + |, + 5 + 0 + action=Action|doc.reference=Document|icon.theme=Icon theme|locale=Language|rendering.defaultsyntax=Default syntax|rendering.restricted=Restricted|rendering.targetsyntax=Target syntax|request.base=Request base URL|request.cookies|request.headers|request.parameters=Request parameters|request.remoteAddr|request.url=Request URL|request.wiki=Request wiki|user=User|wiki=Wiki + com.xpn.xwiki.objects.classes.StaticListClass + + + 0 + 0 + select + + async_enabled + 2 + Asynchronous rendering + 0 + com.xpn.xwiki.objects.classes.BooleanClass + + + 0 + Text + content + 1 + Executed Content + 0 + 25 + 120 + 0 + com.xpn.xwiki.objects.classes.TextAreaClass + + + 0 + extensionPointId + 5 + Extension Point ID + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + 0 + name + 6 + Extension ID + 30 + 0 + com.xpn.xwiki.objects.classes.StringClass + + + PureText + 0 + PureText + parameters + 7 + Extension Parameters + 0 + 10 + 40 + 0 + com.xpn.xwiki.objects.classes.TextAreaClass + + + 0 + 0 + select + forbidden + 0 + 0 + scope + 8 + Extension Scope + 0 + + |, + 1 + 0 + wiki=Current Wiki|user=Current User|global=Global + com.xpn.xwiki.objects.classes.StaticListClass + + + + 0 + + + + + + 0 + + + {{velocity}} +#set ($reference = $services.model.createDocumentReference("xwiki", ["EntraID"], "WebPreferences")) +#if ($services.licensing.licensor.hasLicensureForEntity($references)) + #set ($discard = $xwiki.jsx.use('EntraID.WebHome')) + {{html clean='false'}} + #if ($isGuest && $services.entraid.isXWikiLoginEnabled()) + #set($loginURL = $xwiki.getURL('XWiki.XWikiLogin', 'login', + "xredirect=$request.getRequestURL()&loginLink=1&oidc.skipped=true")) + <a id="tmLogin-bypass" href="${loginURL}">$services.icon.renderHTML('log-in') <i>$escapetool.xml( + $services.localization.render('entra.drawer.header.login'))</i></a> + #elseif ($services.entraid.shouldDisplayXWikiLogin()) + #set($switchToXWikiUser = "${request.getContextPath()}/rest/entraid/login/xwiki/$escapetool.xml( + $services.model.serialize($doc.getDocumentReference(), 'default'))") + #set($logoutURL = $xwiki.getURL('XWiki.XWikiLogout', 'logout', "xredirect=${switchToXWikiUser}")) + <a id="tmLogout-xwiki-switch" href="${logoutURL}">$services.icon.renderHTML('log-in') <i>$escapetool.xml( + $services.localization.render('entra.drawer.header.switch'))</i></a> + #end + {{/html}} +#end +{{/velocity}} + + + org.xwiki.plaftorm.drawer.header + + + com.xwiki.entra.drawer.header + + + + + + wiki + + +