├── DotNetNuke.Authentication.Azure ├── admin │ └── personaBar │ │ ├── css │ │ └── AzureAD.css │ │ ├── AzureAD.html │ │ └── scripts │ │ └── AzureAD.js ├── AzureAD.Web │ ├── webpack.build.cmd │ ├── webpack.run.cmd │ ├── src │ │ ├── actions │ │ │ └── index.js │ │ ├── constants │ │ │ └── actionTypes │ │ │ │ ├── index.js │ │ │ │ └── settings.js │ │ ├── components │ │ │ ├── advanced │ │ │ │ ├── more │ │ │ │ │ └── index.jsx │ │ │ │ ├── sync │ │ │ │ │ └── index.jsx │ │ │ │ └── advancedSettings.less │ │ │ ├── general │ │ │ │ ├── index.jsx │ │ │ │ ├── img │ │ │ │ │ └── AAD.png │ │ │ │ └── generalSettings.less │ │ │ ├── images │ │ │ │ └── performance-management.png │ │ │ ├── style.less │ │ │ ├── svg │ │ │ │ └── error.svg │ │ │ ├── roleMappings │ │ │ │ ├── roleMappingEditor │ │ │ │ │ ├── style.less │ │ │ │ │ └── index.jsx │ │ │ │ ├── roleMappingRow │ │ │ │ │ ├── style.less │ │ │ │ │ └── index.jsx │ │ │ │ └── style.less │ │ │ ├── userMappings │ │ │ │ ├── userMappingEditor │ │ │ │ │ ├── style.less │ │ │ │ │ └── index.jsx │ │ │ │ ├── userMappingRow │ │ │ │ │ ├── style.less │ │ │ │ │ └── index.jsx │ │ │ │ ├── style.less │ │ │ │ └── index.jsx │ │ │ ├── profileMappings │ │ │ │ ├── profileMappingEditor │ │ │ │ │ └── style.less │ │ │ │ ├── profileMappingRow │ │ │ │ │ ├── style.less │ │ │ │ │ └── index.jsx │ │ │ │ └── style.less │ │ │ └── App.jsx │ │ ├── containers │ │ │ ├── Root.js │ │ │ ├── Root.prod.js │ │ │ └── Root.dev.js │ │ ├── reducers │ │ │ ├── rootReducer.js │ │ │ └── settingsReducer.js │ │ ├── resources │ │ │ └── index.jsx │ │ ├── utils │ │ │ └── index.jsx │ │ ├── store │ │ │ └── configureStore.js │ │ ├── globals │ │ │ └── application.js │ │ ├── main.jsx │ │ └── services │ │ │ └── applicationService.js │ ├── .eslintignore │ ├── .npmrc │ ├── jsconfig.json │ ├── .vscode │ │ └── tasks.json │ ├── .babelrc │ ├── .eslintrc.js │ ├── package.json │ ├── .eslintskipwords.js │ └── webpack.config.js ├── Images │ ├── azure.png │ ├── azure-bg.png │ ├── azure-login.png │ └── dnn-webapp.png ├── Logoff.ascx ├── Properties │ └── AssemblyInfo.cs ├── Settings.ascx ├── Logoff.ascx.designer.cs ├── Settings.ascx.designer.cs ├── Data │ ├── IUserMappingsRepository.cs │ ├── IRoleMappingsRepository.cs │ ├── IProfileMappingsRepository.cs │ ├── UserMappingsRepository.cs │ ├── RoleMappingsRepository.cs │ └── ProfileMappingsRepository.cs ├── Providers │ └── DataProviders │ │ └── SqlDataProvider │ │ ├── 03.00.00.SqlDataProvider │ │ ├── 04.03.00.SqlDataProvider │ │ ├── uninstall.SqlDataProvider │ │ └── 04.00.00.SqlDataProvider ├── Login.ascx ├── Components │ ├── Models │ │ ├── RoleMapping.cs │ │ ├── UserMapping.cs │ │ └── ProfileMapping.cs │ ├── IAadController.cs │ ├── Graph │ │ ├── GraphServiceClientFactory.cs │ │ └── GraphExtensions.cs │ ├── State.cs │ ├── FeatureController.cs │ ├── MenuController.cs │ └── AzureUserData.cs ├── DotNetNuke.Authentication.Azure.nuspec ├── module.css ├── AzureADLicense.txt ├── Logoff.ascx.cs ├── Login.ascx.designer.cs ├── Settings.ascx.cs ├── Services │ ├── Hello.cs │ ├── AuthorizationController.cs │ └── AzureADProviderSettings.cs ├── DotNetNuke.Authentication.Azure.sln ├── app.config ├── Auth │ └── AadAuthMessageHandler.cs ├── packages.config ├── Login.ascx.cs └── App_LocalResources │ ├── Settings.ascx.resx │ └── Login.ascx.resx ├── docs └── images │ ├── DNNAzureADv3_1.png │ ├── DNNAzureADv3_2.png │ ├── DNNAzureADv3_3.png │ ├── DNNAzureADv3_4.png │ ├── DNNAzureADv3_5.png │ ├── DNNAzureADv3_6.png │ ├── DNNAzureADv4_1.png │ ├── DNNAzureADv4_2.png │ ├── DNNAzureADv4_3.png │ ├── DNNAzureADv4_4.png │ ├── DNNAzureADv4_settings_adv_more.png │ ├── DNNAzureADv4_settings_adv_sync.png │ ├── DNNAzureADv4_settings_general.png │ ├── DNNAzureADv4_settings_mappings_user.png │ └── DNNAzureAD_LatestRelease.svg ├── DotNetNuke.Authentication.Azure.Extensibility ├── Interfaces │ └── ILoginValidation.cs ├── Properties │ └── AssemblyInfo.cs └── DotNetNuke.Authentication.Azure.Extensibility.csproj ├── LICENSE └── .gitignore /DotNetNuke.Authentication.Azure/admin/personaBar/css/AzureAD.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/webpack.build.cmd: -------------------------------------------------------------------------------- 1 | cls 2 | SET NODE_ENV=production&& webpack --mode=production 3 | -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_1.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_2.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_3.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_4.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_5.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv3_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv3_6.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_1.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_2.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_3.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_4.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/admin/personaBar/AzureAD.html: -------------------------------------------------------------------------------- 1 |
2 |
-------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/webpack.run.cmd: -------------------------------------------------------------------------------- 1 | cls 2 | SET NODE_ENV=development&&SET CUSTOM_DEV=&& webpack-dev-server 3 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/actions/index.js: -------------------------------------------------------------------------------- 1 | import settings from "./settings"; 2 | 3 | export { 4 | settings 5 | }; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/constants/actionTypes/index.js: -------------------------------------------------------------------------------- 1 | import settings from "./settings"; 2 | 3 | export { 4 | settings 5 | }; -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_settings_adv_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_settings_adv_more.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_settings_adv_sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_settings_adv_sync.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_settings_general.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_settings_general.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/advanced/more/index.jsx: -------------------------------------------------------------------------------- 1 | import MoreSettings from "./moreSettings"; 2 | 3 | export default MoreSettings; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/advanced/sync/index.jsx: -------------------------------------------------------------------------------- 1 | import SyncSettings from "./syncSettings"; 2 | 3 | export default SyncSettings; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Images/azure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/Images/azure.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/general/index.jsx: -------------------------------------------------------------------------------- 1 | import GeneralSettings from "./generalSettings"; 2 | 3 | export default GeneralSettings; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Images/azure-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/Images/azure-bg.png -------------------------------------------------------------------------------- /docs/images/DNNAzureADv4_settings_mappings_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/docs/images/DNNAzureADv4_settings_mappings_user.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.eslintignore: -------------------------------------------------------------------------------- 1 | src/components/contentTypeModal/fieldDefinitions/FileUpload/Dropzone.jsx 2 | /src/vendor/** 3 | /src/utils/masker.js -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Images/azure-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/Images/azure-login.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Images/dnn-webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/Images/dnn-webapp.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Logoff.ascx: -------------------------------------------------------------------------------- 1 | <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Logoff.ascx.cs" Inherits="DotNetNuke.Authentication.Azure.Logoff" %> 2 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/Properties/AssemblyInfo.cs -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.npmrc: -------------------------------------------------------------------------------- 1 | @dnnsoftware:registry=https://intelequia.pkgs.visualstudio.com/Dnn.React.Common/_packaging/dnn-public/npm/registry/ 2 | always-auth=true -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/general/img/AAD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/general/img/AAD.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/images/performance-management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/HEAD/DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/images/performance-management.png -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/containers/Root.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | if (process.env.NODE_ENV === "production") { 3 | module.exports = require("./Root.prod"); 4 | } else { 5 | module.exports = require("./Root.dev"); 6 | } 7 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/reducers/rootReducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | import settings from "./settingsReducer"; 3 | 4 | const rootReducer = combineReducers({ 5 | settings 6 | }); 7 | 8 | export default rootReducer; 9 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/resources/index.jsx: -------------------------------------------------------------------------------- 1 | import util from "../utils"; 2 | 3 | const resx = { 4 | get(key) { 5 | let moduleName = util.moduleName; 6 | return util.utilities.getResx(moduleName, key); 7 | } 8 | }; 9 | export default resx; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure.Extensibility/Interfaces/ILoginValidation.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | 3 | namespace DotNetNuke.Authentication.Azure.Extensibility 4 | { 5 | public interface ILoginValidation 6 | { 7 | void OnTokenReceived(string authToken, HttpContext context); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/utils/index.jsx: -------------------------------------------------------------------------------- 1 | const utils = { 2 | init(utilities) { 3 | if (!utilities) { 4 | throw new Error("Utilities is undefined."); 5 | } 6 | this.utilities = utilities; 7 | }, 8 | utilities: null 9 | }; 10 | export default utils; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/containers/Root.prod.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from "react"; 2 | import App from "../components/App"; 3 | 4 | class Root extends Component { 5 | render() { 6 | return ( 7 |
8 | 9 |
10 | ); 11 | } 12 | } 13 | 14 | export default Root; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=759670 3 | // for the documentation about the jsconfig.json format 4 | "compilerOptions": { 5 | "target": "es6", 6 | "module": "commonjs", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "exclude": [ 10 | "node_modules" 11 | ] 12 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/containers/Root.dev.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from "react"; 2 | import App from "../components/App"; 3 | 4 | class Root extends Component { 5 | render() { 6 | return ( 7 |
8 | 9 |
10 | ); 11 | } 12 | } 13 | 14 | export default Root; 15 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "webpack", 9 | "problemMatcher": [] 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/style.less: -------------------------------------------------------------------------------- 1 | #azureAD-container { 2 | 3 | @primary-blue-color: #02a1e6; 4 | 5 | .dnn-persona-bar-page-body .persona-bar-page-body { 6 | 7 | .dnn-switch-container .dnn-switch.place-left { 8 | margin-left: 0px; 9 | } 10 | 11 | button.dnn-ui-common-button[role=primary] { 12 | margin-left: 10px; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-react" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-transform-react-jsx", 8 | "@babel/plugin-proposal-object-rest-spread", 9 | "react-hot-loader/babel" 10 | ], 11 | "env": { 12 | "production": { 13 | "plugins": [ 14 | "transform-react-remove-prop-types" 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Settings.ascx: -------------------------------------------------------------------------------- 1 | <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Settings.ascx.cs" Inherits="DotNetNuke.Authentication.Azure.Settings" %> 2 | <%@ Register TagPrefix="dnn" Namespace="DotNetNuke.UI.WebControls" Assembly="DotNetNuke" %> 3 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Logoff.ascx.designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace DotNetNuke.Authentication.Azure { 11 | 12 | 13 | public partial class Logoff { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Settings.ascx.designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace DotNetNuke.Authentication.Azure { 11 | 12 | 13 | public partial class Settings { 14 | 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/IUserMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using System.Linq; 3 | 4 | namespace DotNetNuke.Authentication.Azure.Data 5 | { 6 | public interface IUserMappingsRepository 7 | { 8 | IQueryable GetUserMappings(int portalId); 9 | UserMapping GetUserMapping(string dnnPropertyName, int portalId); 10 | void UpdateUserMapping(string dnnPropertyName, string aadClaimName, int portalId); 11 | void InsertUserMapping(string dnnPropertyName, string aadClaimName, int portalId); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from "redux"; 2 | import thunkMiddleware from "redux-thunk"; 3 | import reduxImmutableStateInvariant from "redux-immutable-state-invariant"; 4 | import rootReducer from "../reducers/rootReducer"; 5 | 6 | export default function configureStore(initialState) { 7 | const store = createStore( 8 | rootReducer, 9 | initialState, 10 | compose( 11 | applyMiddleware(thunkMiddleware, 12 | reduxImmutableStateInvariant()), 13 | ) 14 | ); 15 | return store; 16 | } 17 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Providers/DataProviders/SqlDataProvider/03.00.00.SqlDataProvider: -------------------------------------------------------------------------------- 1 | UPDATE {databaseOwner}[{objectQualifier}PortalSettings] 2 | SET SettingName = 'Azure_TenantId' 3 | , SettingValue = RIGHT(SUBSTRING(SettingValue, 0, CHARINDEX('/oauth2/authorize', SettingValue)), CHARINDEX('/', REVERSE(SUBSTRING(SettingValue, 0, CHARINDEX('/oauth2/authorize', SettingValue))) + '/') - 1) 4 | WHERE SettingName = 'Azure_AuthorizationEndpoint' 5 | GO 6 | 7 | DELETE {databaseOwner}[{objectQualifier}PortalSettings] 8 | WHERE SettingName = 'Azure_GraphEndpoint' 9 | OR SettingName = 'Azure_TokenEndpoint' 10 | OR SettingName = 'Azure_AppIdUri' 11 | GO 12 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/IRoleMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using System.Linq; 3 | 4 | namespace DotNetNuke.Authentication.Azure.Data 5 | { 6 | public interface IRoleMappingsRepository 7 | { 8 | IQueryable GetRoleMappings(int portalId); 9 | RoleMapping GetRoleMapping(string dnnRoleName, int portalId); 10 | void UpdateRoleMapping(string originalDnnRoleName, string dnnRoleName, string aadRoleName, int portalId); 11 | void InsertRoleMapping(string dnnRoleName, string aadRoleName, int portalId); 12 | void DeleteRoleMapping(string dnnRoleName, int portalId); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/IProfileMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using System.Linq; 3 | 4 | namespace DotNetNuke.Authentication.Azure.Data 5 | { 6 | public interface IProfileMappingsRepository 7 | { 8 | IQueryable GetProfileMappings(int portalId); 9 | ProfileMapping GetProfileMapping(string dnnProfilePropertyName, int portalId); 10 | void UpdateProfileMapping(string dnnProfilePropertyName, string aadClaimName, int portalId); 11 | void InsertProfileMapping(string dnnProfilePropertyName, string aadClaimName, int portalId); 12 | void DeleteProfileMapping(string dnnProfilePropertyName, int portalId); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/globals/application.js: -------------------------------------------------------------------------------- 1 | import utilities from "../utils"; 2 | const boilerPlate = { 3 | init() { 4 | // This setting is required and define the public path 5 | // to allow the web application to download assets on demand 6 | // eslint-disable-next-line no-undef 7 | // __webpack_public_path__ = options.publicPath; 8 | let options = window.dnn.initAzureAD(); 9 | 10 | utilities.init(options.utility); 11 | utilities.moduleName = options.moduleName; 12 | 13 | }, 14 | dispatch() { 15 | throw new Error("dispatch method needs to be overwritten from the Redux store"); 16 | } 17 | }; 18 | 19 | 20 | export default boilerPlate; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render } from "react-dom"; 3 | import { Provider } from "react-redux"; 4 | import configureStore from "./store/configureStore"; 5 | import Root from "./containers/Root"; 6 | import application from "./globals/application"; 7 | 8 | let store = configureStore({enabled: false, instrumentationKey: ""}); 9 | 10 | application.dispatch = store.dispatch; 11 | application.init(); 12 | 13 | const appContainer = document.getElementById("azureAD-container"); 14 | const initCallback = appContainer.getAttribute("data-init-callback"); 15 | application.init(initCallback); 16 | 17 | render( 18 | 19 | 20 | , 21 | appContainer 22 | ); 23 | 24 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/svg/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Login.ascx: -------------------------------------------------------------------------------- 1 | <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Login.ascx.cs" Inherits="DotNetNuke.Authentication.Azure.Login" %> 2 | <%@ Register TagPrefix="dnnC" Namespace="DotNetNuke.Web.Client.ClientResourceManagement" Assembly="DotNetNuke.Web.Client" %> 3 | 4 | 5 | 6 |
  • 7 | 8 | <%=LocalizeString("LoginAzure")%> 9 | 10 |
  • 11 |
  • 12 | 13 | <%=LocalizeString("RegisterAzure") %> 14 | 15 |
  • 16 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/Models/RoleMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Caching; 3 | using DotNetNuke.ComponentModel.DataAnnotations; 4 | 5 | namespace DotNetNuke.Authentication.Azure.Components.Models 6 | { 7 | [TableName("AzureAD_RoleMappings")] 8 | //setup the primary key for table 9 | [PrimaryKey("RoleMappingId", AutoIncrement = true)] 10 | //configure caching using PetaPoco 11 | [Cacheable("RoleMapping", CacheItemPriority.Default, 20)] 12 | public class RoleMapping 13 | { 14 | public int RoleMappingId { get; set; } 15 | 16 | public string DnnRoleName { get; set; } 17 | public string AadRoleName { get; set; } 18 | public int PortalId { get; set; } 19 | public int CreatedByUserId { get; set; } 20 | public DateTime CreatedOnDate { get; set; } 21 | public int LastModifiedByUserId { get; set; } 22 | public DateTime LastModifiedOnDate { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/Models/UserMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Caching; 3 | using DotNetNuke.ComponentModel.DataAnnotations; 4 | 5 | namespace DotNetNuke.Authentication.Azure.Components.Models 6 | { 7 | [TableName("AzureAD_UserMappings")] 8 | //setup the primary key for table 9 | [PrimaryKey("UserMappingId", AutoIncrement = true)] 10 | //configure caching using PetaPoco 11 | [Cacheable("UserMapping", CacheItemPriority.Default, 20)] 12 | public class UserMapping 13 | { 14 | public int UserMappingId { get; set; } 15 | 16 | public string DnnPropertyName { get; set; } 17 | public string AadClaimName { get; set; } 18 | public int PortalId { get; set; } 19 | public int CreatedByUserId { get; set; } 20 | public DateTime CreatedOnDate { get; set; } 21 | public int LastModifiedByUserId { get; set; } 22 | public DateTime LastModifiedOnDate { get; set; } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/Models/ProfileMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Caching; 3 | using DotNetNuke.ComponentModel.DataAnnotations; 4 | 5 | namespace DotNetNuke.Authentication.Azure.Components.Models 6 | { 7 | [TableName("AzureAD_ProfileMappings")] 8 | //setup the primary key for table 9 | [PrimaryKey("ProfileMappingId", AutoIncrement = true)] 10 | //configure caching using PetaPoco 11 | [Cacheable("ProfileMapping", CacheItemPriority.Default, 20)] 12 | public class ProfileMapping 13 | { 14 | public int ProfileMappingId { get; set; } 15 | 16 | public string DnnProfilePropertyName { get; set; } 17 | public string AadClaimName { get; set; } 18 | public int PortalId { get; set; } 19 | public int CreatedByUserId { get; set; } 20 | public DateTime CreatedOnDate { get; set; } 21 | public int LastModifiedByUserId { get; set; } 22 | public DateTime LastModifiedOnDate { get; set; } 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/DotNetNuke.Authentication.Azure.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DotNetNuke.Authentication.Azure 5 | 4.4.5 6 | DotNetNuke.Authentication.Azure 7 | Intelequia 8 | Intelequia 9 | https://raw.githubusercontent.com/davidjrh/dnn.azureadprovider/master/LICENSE 10 | https://github.com/davidjrh/dnn.azureadprovider 11 | https://intelequia.com/favicon-32x32.png 12 | false 13 | Microsoft Entra ID Authentication provider library 14 | See https://github.com/davidjrh/dnn.azureadprovider/releases 15 | Copyright 2023 16 | Intelequia DNN AzureAD 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Providers/DataProviders/SqlDataProvider/04.03.00.SqlDataProvider: -------------------------------------------------------------------------------- 1 | /* Setup default values for new setting for separate Graph TenantId to the current tenantId */ 2 | 3 | INSERT INTO {databaseOwner}[{objectQualifier}PortalSettings] 4 | (PortalID, SettingName, SettingValue, CreatedByUserID, CreatedOnDate, LastModifiedByUserID, LastModifiedOnDate, CultureCode, IsSecure) 5 | SELECT PortalID, 'Azure_AADTenantId', SettingValue, CreatedByUserID, GETUTCDATE(), LastModifiedByUserID, GETUTCDATE(), CultureCode, IsSecure 6 | FROM {databaseOwner}[{objectQualifier}PortalSettings] 7 | WHERE SettingName='Azure_TenantId' 8 | 9 | INSERT INTO {databaseOwner}[{objectQualifier}HostSettings] 10 | (SettingName, SettingValue, SettingIsSecure, CreatedByUserID, CreatedOnDate, LastModifiedByUserID, LastModifiedOnDate) 11 | SELECT 'Azure_AADTenantId', SettingValue, SettingIsSecure, CreatedByUserID, GETUTCDATE(), LastModifiedByUserID, GETUTCDATE() 12 | FROM {databaseOwner}[{objectQualifier}HostSettings] 13 | WHERE SettingName='Azure_TenantId' 14 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/constants/actionTypes/settings.js: -------------------------------------------------------------------------------- 1 | const settingsActionTypes = { 2 | SWITCH_TAB: "SWITCH_TAB", 3 | RETRIEVED_SETTINGS: "RETRIEVED_SETTINGS", 4 | UPDATED_SETTINGS: "UPDATED_SETTINGS", 5 | UPDATED_PROFILEMAPPING: "UPDATED_PROFILEMAPPING", 6 | SETTINGS_CLIENT_MODIFIED: "SETTINGS_CLIENT_MODIFIED", 7 | RETRIEVED_PROFILESETTINGS: "RETRIEVED_PROFILESETTINGS", 8 | RETRIEVED_PROFILEPROPERTIES: "RETRIEVED_PROFILEPROPERTIES", 9 | CANCELLED_PROFILEMAPPING_CLIENT_MODIFIED: "CANCELLED_PROFILEMAPPING_CLIENT_MODIFIED", 10 | PROFILEMAPPINGS_CLIENT_MODIFIED: "PROFILEMAPPINGS_CLIENT_MODIFIED", 11 | SWITCH_MAPPING_SUBTAB: "SWITCH_MAPPING_SUBTAB", 12 | RETRIEVED_ROLEMAPPINGSETTINGS: "RETRIEVED_ROLEMAPPINGSETTINGS", 13 | RETRIEVED_AVAILABLEROLES: "RETRIEVED_AVAILABLEROLES", 14 | ROLEMAPPINGS_CLIENT_MODIFIED: "ROLEMAPPINGS_CLIENT_MODIFIED", 15 | RETRIEVED_USERMAPPINGSETTINGS: "RETRIEVED_USERMAPPINGSETTINGS", 16 | USERMAPPINGS_CLIENT_MODIFIED: "USERMAPPINGS_CLIENT_MODIFIED" 17 | }; 18 | export default settingsActionTypes; -------------------------------------------------------------------------------- /docs/images/DNNAzureAD_LatestRelease.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | release 14 | release 15 | v4.5.0 16 | v4.5.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/module.css: -------------------------------------------------------------------------------- 1 | ul.buttonList .azure a span { 2 | padding-left: 45px; 3 | background: url('images/azure-login.png') no-repeat 6px 7px; 4 | } 5 | ul.buttonList .azure a:after { 6 | position: absolute; 7 | left: 35px; 8 | top: 0; 9 | height: 100%; 10 | width: 0; 11 | content: ""; 12 | border-left: 1px solid rgba(0,0,0,0.2); 13 | border-right: 1px solid rgba(255,255,255,0.3); 14 | } 15 | 16 | 17 | /*AZURE*/ 18 | ul.buttonList li.azure a { 19 | background: #00abec url(images/azure-bg.png) repeat-x; 20 | } 21 | ul.buttonList .azure a { 22 | color: #fff; 23 | text-shadow: 0px -1px 0px rgba(0,0,0,0.4); 24 | border-color: #3d82a0; /* dark teal blue */ 25 | background-position: 0; 26 | background-color: #00abec; 27 | } 28 | ul.buttonList .azure a:hover { 29 | color: #fff; 30 | border-color: #3d82a0; /* dark teal blue */ 31 | text-shadow: 0px -1px 0px rgba(0,0,0,0.4); 32 | background-position: 0 -50px; 33 | background-color: #00baff; 34 | } 35 | ul.buttonList .azure a:active { 36 | background-position: 0 -100px; 37 | border-color: #3d82a0; /* dark teal blue */ 38 | background-color: #2680a9; 39 | } 40 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureADLicense.txt: -------------------------------------------------------------------------------- 1 |

    Intelequia 2 |
    Copyright (c) 2010-2026 by Intelequia

    3 |

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    4 |

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    5 |

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Intelequia Technologies. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "plugins": [ 3 | "react" 4 | ], 5 | "env": { 6 | "browser": true, 7 | "commonjs": true 8 | }, 9 | "extends": ["eslint:recommended", "plugin:react/recommended"], 10 | "settings": { 11 | "react": { 12 | "version": "16" 13 | } 14 | }, 15 | "parserOptions": { 16 | "ecmaFeatures": { 17 | "jsx": true 18 | }, 19 | "ecmaVersion": 2018, 20 | "sourceType": "module" 21 | }, 22 | "globals": { 23 | "__": false, 24 | "Promise": false, 25 | "VERSION": false 26 | }, 27 | "rules": { 28 | "semi": "error", 29 | "no-var": "error", 30 | "quotes": ["warn", "double" ], 31 | "indent": ["warn", 4, {"SwitchCase": 1}], 32 | "no-unused-vars": "warn", 33 | "no-console": "warn", 34 | "keyword-spacing": "warn", 35 | "eqeqeq": "warn", 36 | "space-before-function-paren": ["warn", { "anonymous": "always", "named": "never" }], 37 | "space-before-blocks": "warn", 38 | "no-multiple-empty-lines": "warn", 39 | "react/jsx-equals-spacing": ["warn", "never"], 40 | "id-match": ["error", "^([A-Za-z0-9_])+$", {"properties": true}] 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/general/generalSettings.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index"; 2 | .dnn-azuread-generalSettings { 3 | box-sizing: border-box; 4 | padding: 35px 25px; 5 | * { 6 | box-sizing: border-box; 7 | } 8 | h1 { 9 | margin-top: 30px; 10 | margin-bottom: 15px; 11 | text-transform: uppercase; 12 | } 13 | .panel-description { 14 | margin-bottom: 30px; 15 | } 16 | .logo { 17 | float: right; 18 | background-image: url(img/AAD.png); 19 | background-repeat: no-repeat; 20 | background-size: 70px; 21 | width: 80px; 22 | height: 80px; 23 | } 24 | p { 25 | margin-bottom: 20px; 26 | } 27 | .dnn-switch-container { 28 | width: 90%; 29 | } 30 | .directory-section { 31 | margin-top: 10px; 32 | } 33 | .editor-row { 34 | display: inline-block; 35 | width: 90%; 36 | } 37 | .input-full-row { 38 | width: 95%; 39 | } 40 | .dnn-single-line-input-with-error { 41 | width: 100%; 42 | padding-bottom: 15px; 43 | } 44 | .dnn-ui-common-single-line-input.small { 45 | margin-bottom: 0px!important; 46 | } 47 | .buttons-box { 48 | margin-top: 50px; 49 | margin-bottom: 30px; 50 | button.dnn-ui-common-button[role=primary] { 51 | margin-left: 10px; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/IAadController.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2019 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | using System.Net.Http; 25 | 26 | namespace DotNetNuke.Authentication.Azure.Components 27 | { 28 | public interface IAadController 29 | { 30 | string SchemeType { get; } 31 | string ValidateToken(HttpRequestMessage request); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure.Extensibility/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetNuke.Authentication.Azure.Extensibility")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Intelequia")] 12 | [assembly: AssemblyProduct("DotNetNuke.Authentication.Azure.Extensibility")] 13 | [assembly: AssemblyCopyright("Copyright © 2025")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("42445032-9098-4160-930d-4127dc292695")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.1.0")] 36 | [assembly: AssemblyFileVersion("1.0.1.0")] 37 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/Graph/GraphServiceClientFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graph; 2 | using System; 3 | using System.Net.Http; 4 | using System.Net.Http.Headers; 5 | using System.Reflection; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNetNuke.Authentication.Azure.Components.Graph 9 | { 10 | internal static class GraphServiceClientFactory 11 | { 12 | public static GraphServiceClient GetAuthenticatedGraphClient( 13 | Func> acquireAccessToken) 14 | { 15 | return new GraphServiceClient( 16 | new CustomAuthenticationProvider(acquireAccessToken) 17 | ); 18 | } 19 | } 20 | 21 | class CustomAuthenticationProvider : IAuthenticationProvider 22 | { 23 | private readonly Func> _acquireAccessToken; 24 | public CustomAuthenticationProvider(Func> acquireAccessToken) 25 | { 26 | _acquireAccessToken = acquireAccessToken; 27 | } 28 | 29 | public async Task AuthenticateRequestAsync(HttpRequestMessage requestMessage) 30 | { 31 | var accessToken = await _acquireAccessToken.Invoke(); 32 | 33 | // Add the token in the Authorization header 34 | requestMessage.Headers.Authorization = new AuthenticationHeaderValue( 35 | "Bearer", accessToken 36 | ); 37 | string version = CustomAttributeExtensions.GetCustomAttribute((Assembly.GetExecutingAssembly()))?.Version; 38 | requestMessage.Headers.Add("User-Agent", $"DNN Azure AD Provider (v{version})"); 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/roleMappings/roleMappingEditor/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .rolemapping-editor { 3 | float: left; 4 | margin: 20px 30px; 5 | .topMessage { 6 | border: 1px solid @alto; 7 | padding: 10px 20px; 8 | background-color: @mercury; 9 | margin: 0 0 20px 0; 10 | } 11 | .dnn-ui-common-input-group { 12 | padding: 0 0 15px 0; 13 | label { 14 | font-weight: bolder; 15 | float: left; 16 | } 17 | .dnn-label { 18 | margin: 8px 0; 19 | } 20 | .dnn-dropdown,.dnn-dropdown-with-error 21 | { 22 | width: 100% !important; 23 | box-sizing: border-box; 24 | } 25 | .dnn-single-line-input-with-error { 26 | width: 100% !important; 27 | } 28 | } 29 | .dnn-grid-system { 30 | .left-column { 31 | padding-right: 30px; 32 | border-right: 1px solid @alto; 33 | } 34 | .right-column { 35 | padding-left: 30px; 36 | border-left: 0 !important; 37 | } 38 | } 39 | .editor-buttons-box { 40 | width: 100%; 41 | text-align: center; 42 | float: left; 43 | margin: 30px 0 0 0; 44 | .dnn-ui-common-button { 45 | margin: 5px; 46 | } 47 | .edit-icon { 48 | margin: 0px 10px 20px 10px; 49 | float: right; 50 | svg { 51 | width: 16px; 52 | float: left; 53 | height: 16px; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/userMappingEditor/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .usermapping-editor { 3 | float: left; 4 | margin: 20px 30px; 5 | .topMessage { 6 | border: 1px solid @alto; 7 | padding: 10px 20px; 8 | background-color: @mercury; 9 | margin: 0 0 20px 0; 10 | } 11 | .dnn-ui-common-input-group { 12 | padding: 0 0 15px 0; 13 | label { 14 | font-weight: bolder; 15 | float: left; 16 | } 17 | .dnn-label { 18 | margin: 8px 0; 19 | } 20 | .dnn-dropdown,.dnn-dropdown-with-error 21 | { 22 | width: 100% !important; 23 | box-sizing: border-box; 24 | } 25 | .dnn-single-line-input-with-error { 26 | width: 100% !important; 27 | } 28 | } 29 | .dnn-grid-system { 30 | .left-column { 31 | padding-right: 30px; 32 | border-right: 1px solid @alto; 33 | } 34 | .right-column { 35 | padding-left: 30px; 36 | border-left: 0 !important; 37 | } 38 | } 39 | .editor-buttons-box { 40 | width: 100%; 41 | text-align: center; 42 | float: left; 43 | margin: 30px 0 0 0; 44 | .dnn-ui-common-button { 45 | margin: 5px; 46 | } 47 | .edit-icon { 48 | margin: 0px 10px 20px 10px; 49 | float: right; 50 | svg { 51 | width: 16px; 52 | float: left; 53 | height: 16px; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/profileMappings/profileMappingEditor/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .profilemapping-editor { 3 | float: left; 4 | margin: 20px 30px; 5 | .topMessage { 6 | border: 1px solid @alto; 7 | padding: 10px 20px; 8 | background-color: @mercury; 9 | margin: 0 0 20px 0; 10 | } 11 | .dnn-ui-common-input-group { 12 | padding: 0 0 15px 0; 13 | label { 14 | font-weight: bolder; 15 | float: left; 16 | } 17 | .dnn-label { 18 | margin: 8px 0; 19 | } 20 | .dnn-dropdown,.dnn-dropdown-with-error 21 | { 22 | width: 100% !important; 23 | box-sizing: border-box; 24 | } 25 | .dnn-single-line-input-with-error { 26 | width: 100% !important; 27 | } 28 | } 29 | .dnn-grid-system { 30 | .left-column { 31 | padding-right: 30px; 32 | border-right: 1px solid @alto; 33 | } 34 | .right-column { 35 | padding-left: 30px; 36 | border-left: 0 !important; 37 | } 38 | } 39 | .editor-buttons-box { 40 | width: 100%; 41 | text-align: center; 42 | float: left; 43 | margin: 30px 0 0 0; 44 | .dnn-ui-common-button { 45 | margin: 5px; 46 | } 47 | .edit-icon { 48 | margin: 0px 10px 20px 10px; 49 | float: right; 50 | svg { 51 | width: 16px; 52 | float: left; 53 | height: 16px; 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/advanced/advancedSettings.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index"; 2 | .dnn-azuread-aad-advancedSettings { 3 | box-sizing: border-box; 4 | padding: 35px 25px; 5 | * { 6 | box-sizing: border-box; 7 | } 8 | h1 { 9 | margin-top: 10px; 10 | margin-bottom: 10px; 11 | text-transform: uppercase; 12 | } 13 | p { 14 | margin-bottom: 20px; 15 | } 16 | .dnn-switch-container { 17 | width: 90%; 18 | } 19 | .editor-row { 20 | display: inline-block; 21 | width: 90%; 22 | } 23 | .dnn-single-line-input-with-error { 24 | width: 100%; 25 | padding-bottom: 15px; 26 | } 27 | .dnn-ui-common-single-line-input.small { 28 | margin-bottom: 0px!important; 29 | } 30 | .dnn-dropdown-with-error { 31 | width: 90%; 32 | } 33 | .buttons-box { 34 | margin-top: 50px; 35 | margin-bottom: 30px; 36 | button.dnn-ui-common-button[role=primary] { 37 | margin-left: 10px; 38 | } 39 | } 40 | .warning-container { 41 | width: 100%; 42 | float: left; 43 | margin: 10px 0 15px 0; 44 | font-weight: bolder; 45 | color: @alizarinCrimson; 46 | .collapsible-content { 47 | margin-top: 5px; 48 | > div { 49 | border: solid 1px; 50 | } 51 | } 52 | .warning-icon { 53 | > svg { 54 | width: 17px; 55 | float: left; 56 | height: 17px; 57 | margin: 0 10px 0 0; 58 | } 59 | } 60 | .warning-msg { 61 | margin-left: 30px; 62 | } 63 | } 64 | h1.spacer { 65 | margin-top: 25px; 66 | } 67 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Logoff.ascx.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2010-2017 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | #region Usings 25 | 26 | using System; 27 | using DotNetNuke.Authentication.Azure.Components; 28 | using DotNetNuke.Services.Authentication; 29 | 30 | #endregion 31 | 32 | namespace DotNetNuke.Authentication.Azure 33 | { 34 | public partial class Logoff : AuthenticationLogoffBase 35 | { 36 | protected override void OnInit(EventArgs e) 37 | { 38 | base.OnInit(e); 39 | var oauthClient = new AzureClient(PortalId, AuthMode.Login); 40 | oauthClient.Logout(); 41 | OnLogOff(e); 42 | OnRedirect(e); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Login.ascx.designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // Changes to this file may cause incorrect behavior and will be lost if 6 | // the code is regenerated. 7 | // 8 | //------------------------------------------------------------------------------ 9 | 10 | namespace DotNetNuke.Authentication.Azure { 11 | 12 | 13 | public partial class Login { 14 | 15 | /// 16 | /// AzureCss control. 17 | /// 18 | /// 19 | /// Auto-generated field. 20 | /// To modify move field declaration from designer file to code-behind file. 21 | /// 22 | // protected global::DotNetNuke.Web.Client.ClientResourceManagement.DnnCssInclude AzureCss; 23 | 24 | /// 25 | /// loginItem control. 26 | /// 27 | /// 28 | /// Auto-generated field. 29 | /// To modify move field declaration from designer file to code-behind file. 30 | /// 31 | protected global::System.Web.UI.HtmlControls.HtmlGenericControl loginItem; 32 | 33 | /// 34 | /// loginButton control. 35 | /// 36 | /// 37 | /// Auto-generated field. 38 | /// To modify move field declaration from designer file to code-behind file. 39 | /// 40 | protected global::System.Web.UI.WebControls.LinkButton loginButton; 41 | 42 | /// 43 | /// registerItem control. 44 | /// 45 | /// 46 | /// Auto-generated field. 47 | /// To modify move field declaration from designer file to code-behind file. 48 | /// 49 | protected global::System.Web.UI.HtmlControls.HtmlGenericControl registerItem; 50 | 51 | /// 52 | /// registerButton control. 53 | /// 54 | /// 55 | /// Auto-generated field. 56 | /// To modify move field declaration from designer file to code-behind file. 57 | /// 58 | protected global::System.Web.UI.WebControls.LinkButton registerButton; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Settings.ascx.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2010-2017 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | #region Usings 25 | 26 | using System; 27 | using DotNetNuke.Authentication.Azure.Components; 28 | using DotNetNuke.Services.Authentication.OAuth; 29 | 30 | #endregion 31 | 32 | namespace DotNetNuke.Authentication.Azure 33 | { 34 | public partial class Settings : OAuthSettingsBase 35 | { 36 | protected override string AuthSystemApplicationName => "Azure"; 37 | 38 | public override void UpdateSettings() 39 | { 40 | if (SettingsEditor.IsValid && SettingsEditor.IsDirty) 41 | { 42 | var config = (AzureConfig)SettingsEditor.DataSource; 43 | AzureConfig.UpdateConfig(config); 44 | } 45 | } 46 | 47 | protected override void OnLoad(EventArgs e) 48 | { 49 | base.OnLoad(e); 50 | OAuthConfigBase.ClearConfig(AuthSystemApplicationName, PortalId); 51 | var config = AzureConfig.GetConfig(AuthSystemApplicationName, PortalId); 52 | SettingsEditor.DataSource = config; 53 | SettingsEditor.DataBind(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Services/Hello.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2019 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | using DotNetNuke.Web.Api; 25 | using System; 26 | using System.Net; 27 | using System.Net.Http; 28 | using System.Web.Http; 29 | 30 | 31 | namespace DotNetNuke.Authentication.Azure.Services 32 | { 33 | public class RouterMapper : IServiceRouteMapper 34 | { 35 | public void RegisterRoutes(IMapRoute mapRouteManager) 36 | { 37 | mapRouteManager.MapHttpRoute("DotNetNuke.Authentication.Azure.Services", "default", "{controller}/{action}", new[] { "DotNetNuke.Authentication.Azure.Services" }); 38 | } 39 | } 40 | 41 | public class HelloController : DnnApiController 42 | { 43 | [HttpGet] 44 | [DnnAuthorize(AuthTypes = "JWT")] 45 | public HttpResponseMessage Test() 46 | { 47 | try 48 | { 49 | return Request.CreateResponse(HttpStatusCode.OK, $"Hello {UserInfo.DisplayName}"); 50 | } 51 | catch (Exception ex) 52 | { 53 | return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dnn-azure-ad", 3 | "version": "4.2.0", 4 | "private": true, 5 | "description": "DNN Azure AD persona bar settings", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/davidjrh/dnn.azureadprovider.git" 9 | }, 10 | "license": "MIT", 11 | "keywords": [ 12 | "DNN", 13 | "React", 14 | "DNN Module", 15 | "Persona Bar", 16 | "Intelequia", 17 | "Azure AD", 18 | "Office 365" 19 | ], 20 | "scripts": { 21 | "build": "set NODE_ENV=production&&webpack --mode production", 22 | "test": "jest", 23 | "test:watch": "jest --watch", 24 | "debug": "set NODE_ENV=debug&&webpack -p", 25 | "webpack": "webpack-dev-server --mode development --host localhost --port 8080 --hot --history-api-fallback", 26 | "watch": "set NODE_ENV=debug & webpack --mode=development --progress --colors --watch", 27 | "analyze": "set NODE_ENV=production&&webpack -p --json | webpack-bundle-size-analyzer", 28 | "lint": "eslint --fix" 29 | }, 30 | "devDependencies": { 31 | "@babel/core": "^7.1.6", 32 | "@babel/plugin-proposal-object-rest-spread": "^7.2.0", 33 | "@babel/plugin-transform-react-jsx": "^7.2.0", 34 | "@babel/preset-env": "^7.1.6", 35 | "@babel/preset-react": "^7.0.0", 36 | "@dnnsoftware/dnn-react-common": "9.11.0", 37 | "array.prototype.find": "2.0.4", 38 | "array.prototype.findindex": "2.0.2", 39 | "babel-loader": "^8.0.6", 40 | "babel-plugin-transform-react-remove-prop-types": "^0.4.24", 41 | "create-react-class": "^15.6.3", 42 | "css-loader": "2.1.1", 43 | "eslint": "7.32.0", 44 | "eslint-loader": "4.0.2", 45 | "eslint-plugin-jest": "^22.0.0", 46 | "eslint-plugin-react": "7.11.1", 47 | "eslint-plugin-spellcheck": "0.0.11", 48 | "file-loader": "3.0.1", 49 | "jest": "^28.1.2", 50 | "jwt-decode": "2.2.0", 51 | "less": "4.1.2", 52 | "less-loader": "5.0.0", 53 | "prop-types": "^15.6.2", 54 | "raw-loader": "2.0.0", 55 | "react": "^16.6.3", 56 | "react-custom-scrollbars": "4.2.1", 57 | "react-dom": "^16.6.3", 58 | "react-hot-loader": "4.8.5", 59 | "react-modal": "3.6.1", 60 | "react-redux": "^6.0.0", 61 | "redux": "^4.0.1", 62 | "redux-immutable-state-invariant": "^2.1.0", 63 | "redux-thunk": "^2.3.0", 64 | "source-map-loader": "^0.2.3", 65 | "style-loader": "^0.23.1", 66 | "url-loader": "1.1.2", 67 | "webpack": "^4.31.0", 68 | "webpack-bundle-size-analyzer": "3.0.0", 69 | "webpack-cli": "4.10.0", 70 | "webpack-dev-server": "4.11.1" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/State.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetNuke.Authentication.Azure.Components 4 | { 5 | public class State 6 | { 7 | public State() 8 | { 9 | Service = AzureConfig.ServiceName; 10 | PortalId = -1; 11 | Culture = ""; 12 | RedirectUrl = ""; 13 | } 14 | public State(string s) 15 | { 16 | Service = ""; 17 | PortalId = -1; 18 | Culture = ""; 19 | RedirectUrl = ""; 20 | ParseState(s); 21 | } 22 | public string Service { get; set; } 23 | public int PortalId { get; set; } 24 | public string Culture { get; set; } 25 | public string RedirectUrl { get; set; } 26 | public bool IsUserProfile { get; set; } 27 | 28 | public override string ToString() 29 | { 30 | var s = ""; 31 | if (!string.IsNullOrEmpty(Service)) 32 | { 33 | s += $"s={Service}"; 34 | } 35 | if (PortalId != -1) 36 | { 37 | s += $";p={PortalId}"; 38 | } 39 | if (!string.IsNullOrEmpty(Culture)) 40 | { 41 | s += $";c={Culture}"; 42 | } 43 | if (!string.IsNullOrEmpty(RedirectUrl)) 44 | { 45 | s += $";r={Uri.EscapeDataString(RedirectUrl)}"; 46 | } 47 | return s; 48 | } 49 | public void ParseState(string s) 50 | { 51 | if (string.IsNullOrEmpty(s)) 52 | return; 53 | var pairs = s.Split(';'); 54 | foreach (var pair in pairs) 55 | { 56 | var item = pair.Split('='); 57 | if (item.Length == 2) 58 | { 59 | switch (item[0]) 60 | { 61 | case "s": 62 | Service = item[1]; 63 | break; 64 | case "p": 65 | PortalId = int.Parse(item[1]); 66 | break; 67 | case "c": 68 | Culture = item[1]; 69 | break; 70 | case "r": 71 | RedirectUrl = Uri.UnescapeDataString(item[1]); 72 | break; 73 | default: 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/.eslintskipwords.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | "dnn", 3 | "evoq", 4 | "eslint", 5 | "fetch-ie8", 6 | "react-dom", 7 | "lodash", 8 | "bool", 9 | "func", 10 | "dropdown", 11 | "globals", 12 | "init", 13 | "cors", 14 | "api", 15 | "integrations", 16 | "const", 17 | "dom", 18 | "stringify", 19 | "debounce", 20 | "debounced", 21 | "unmount", 22 | "ceil", 23 | "px", 24 | "rgba", 25 | "svg", 26 | "html", 27 | "src", 28 | "calc", 29 | "img", 30 | "jpg", 31 | "nowrap", 32 | "js", 33 | "dropzone", 34 | "ondropactivate", 35 | "ondragenter", 36 | "draggable", 37 | "ondrop", 38 | "ondragleave", 39 | "ondropdeactivate", 40 | "droppable", 41 | "onmove", 42 | "onend", 43 | "interactable", 44 | "webkit", 45 | "rect", 46 | "concat", 47 | "resize", 48 | "sortable", 49 | "socialpanelheader", 50 | "socialpanelbody", 51 | "asc", 52 | "dx", 53 | "dy", 54 | "num", 55 | "reactid", 56 | "currentcolor", 57 | "ui", 58 | "checkbox", 59 | "tooltip", 60 | "scrollbar", 61 | "unshift", 62 | "dragstart", 63 | "contenteditable", 64 | "addons", 65 | "tbody", 66 | "resizable", 67 | "resizemove", 68 | "resizestart", 69 | "resizeend", 70 | "resizing", 71 | "resized", 72 | "ondropmove", 73 | "moz", 74 | "evq", 75 | "btn", 76 | "addon", 77 | "substring", 78 | "jpeg", 79 | "gif", 80 | "pdf", 81 | "png", 82 | "ppt", 83 | "txt", 84 | "autocomplete", 85 | "utils", 86 | "js-htmlencode", 87 | "webpack", 88 | "undef", 89 | "analytics", 90 | "dataset", 91 | "checkmark", 92 | "li", 93 | "br", 94 | "localizations", 95 | "javascript", 96 | "ie", 97 | "pikaday", 98 | "na", 99 | "searchable", 100 | "clearable", 101 | "http", 102 | "decrement", 103 | "ok", 104 | "checkboxes", 105 | "ddmmyy", 106 | "mmddyy", 107 | "ddmmyyyy", 108 | "mmddyyyy", 109 | "yyyymmdd", 110 | "td", 111 | "th", 112 | "marketo", 113 | "salesforce", 114 | "captcha", 115 | "rgb", 116 | "sunday", 117 | "xxxx", 118 | "typeof", 119 | "popup", 120 | "ccc", 121 | "aaf", 122 | "dddd", 123 | "redux", 124 | "middleware", 125 | "dev", 126 | "util", 127 | "searchpanel", 128 | "uncollapse", 129 | "dev", 130 | "ctrl" 131 | ] 132 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Providers/DataProviders/SqlDataProvider/uninstall.SqlDataProvider: -------------------------------------------------------------------------------- 1 | DELETE {databaseOwner}[{objectQualifier}PortalSettings] 2 | WHERE SettingName IN 3 | ( 4 | 'Azure_APIKey' 5 | , 'Azure_APISecret' 6 | , 'Azure_RedirectUri' 7 | , 'Azure_OnErrorUri' 8 | , 'Azure_TenantId' 9 | , 'Azure_AutoRedirect' 10 | , 'Azure_AutoAuthorize' 11 | , 'Azure_AutoMatchExistingUsers' 12 | , 'Azure_Enabled' 13 | , 'Azure_AADTenantId' 14 | , 'Azure_AADApplicationId' 15 | , 'Azure_AADApplicationKey' 16 | , 'Azure_GraphUseCustomParams' 17 | , 'Azure_JwtAudiences' 18 | , 'Azure_RoleSyncEnabled' 19 | , 'Azure_UserSyncEnabled' 20 | , 'Azure_ProfileSyncEnabled' 21 | , 'Azure_JwtAuthEnabled' 22 | , 'Azure_APIResource' 23 | , 'Azure_Scopes' 24 | , 'Azure_UsernamePrefixEnabled' 25 | , 'Azure_GroupNamePrefixEnabled' 26 | , 'Azure_AuthorizationCodePrompt' 27 | , 'Azure_DomainHint' 28 | , 'AzureB2C_UserGlobalSettings' 29 | ) 30 | GO 31 | 32 | DELETE {databaseOwner}[{objectQualifier}HostSettings] 33 | WHERE SettingName IN 34 | ( 35 | 'Azure_APIKey' 36 | , 'Azure_APISecret' 37 | , 'Azure_RedirectUri' 38 | , 'Azure_OnErrorUri' 39 | , 'Azure_TenantId' 40 | , 'Azure_AutoRedirect' 41 | , 'Azure_AutoAuthorize' 42 | , 'Azure_AutoMatchExistingUsers' 43 | , 'Azure_Enabled' 44 | , 'Azure_AADTenantId' 45 | , 'Azure_AADApplicationId' 46 | , 'Azure_AADApplicationKey' 47 | , 'Azure_GraphUseCustomParams' 48 | , 'Azure_JwtAudiences' 49 | , 'Azure_RoleSyncEnabled' 50 | , 'Azure_UserSyncEnabled' 51 | , 'Azure_ProfileSyncEnabled' 52 | , 'Azure_JwtAuthEnabled' 53 | , 'Azure_APIResource' 54 | , 'Azure_Scopes' 55 | , 'Azure_UsernamePrefixEnabled' 56 | , 'Azure_GroupNamePrefixEnabled' 57 | , 'Azure_AuthorizationCodePrompt' 58 | , 'Azure_DomainHint' 59 | , 'AzureB2C_UserGlobalSettings' 60 | ) 61 | GO 62 | 63 | DELETE FROM {databaseOwner}[{objectQualifier}Schedule] 64 | WHERE TypeFullName = 'DotNetNuke.Authentication.Azure.ScheduledTasks.SyncSchedule, DotNetNuke.Authentication.Azure') 65 | GO 66 | 67 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_UserMappings]', N'U') IS NULL 68 | BEGIN 69 | DROP TABLE {databaseOwner}[{objectQualifier}AzureAD_UserMappings] 70 | END 71 | 72 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_ProfileMappings]', N'U') IS NULL 73 | BEGIN 74 | DROP TABLE {databaseOwner}[{objectQualifier}AzureAD_ProfileMappings] 75 | END 76 | 77 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_RoleMappings]', N'U') IS NULL 78 | BEGIN 79 | DROP TABLE {databaseOwner}[{objectQualifier}AzureAD_RoleMappings] 80 | END -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/FeatureController.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2019 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | using DotNetNuke.Entities.Modules; 25 | using System; 26 | using System.Linq; 27 | 28 | namespace DotNetNuke.Authentication.Azure.Components 29 | { 30 | public class FeatureController : IUpgradeable 31 | { 32 | public string UpgradeModule(string version) 33 | { 34 | try 35 | { 36 | var task = DotNetNuke.Services.Scheduling.SchedulingController.GetSchedule().FirstOrDefault(x => x.TypeFullName == "DotNetNuke.Authentication.Azure.ScheduledTasks.SyncSchedule, DotNetNuke.Authentication.Azure"); 37 | if (task != null) 38 | { 39 | DotNetNuke.Services.Scheduling.SchedulingController.UpdateSchedule(task.ScheduleID, 40 | task.TypeFullName, 41 | task.TimeLapse, task.TimeLapseMeasurement, task.RetryTimeLapse, task.RetryTimeLapseMeasurement, 42 | task.RetainHistoryNum, task.AttachToEvent, task.CatchUpEnabled, true, task.ObjectDependencies, 43 | "," + Environment.MachineName + ",", task.FriendlyName); 44 | } 45 | return "Success"; 46 | } 47 | catch (Exception ex) 48 | { 49 | return "Failed: " + ex.Message; 50 | } 51 | } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/DotNetNuke.Authentication.Azure.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32901.215 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetNuke.Authentication.Azure", "DotNetNuke.Authentication.Azure.csproj", "{F5BB1B82-D843-4709-A57E-3A9CC290403F}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{30168D48-BC63-47D3-9C90-75F0C902C8D2}" 9 | ProjectSection(SolutionItems) = preProject 10 | ..\.build\ModulePackage.targets = ..\.build\ModulePackage.targets 11 | ..\.build\MSBuild.Community.Tasks.targets = ..\.build\MSBuild.Community.Tasks.targets 12 | EndProjectSection 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetNuke.Authentication.Azure.Extensibility", "..\DotNetNuke.Authentication.Azure.Extensibility\DotNetNuke.Authentication.Azure.Extensibility.csproj", "{42445032-9098-4160-930D-4127DC292695}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release Legacy|Any CPU = Release Legacy|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Release Legacy|Any CPU.ActiveCfg = Release|Any CPU 26 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Release Legacy|Any CPU.Build.0 = Release|Any CPU 27 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {F5BB1B82-D843-4709-A57E-3A9CC290403F}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {42445032-9098-4160-930D-4127DC292695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {42445032-9098-4160-930D-4127DC292695}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {42445032-9098-4160-930D-4127DC292695}.Release Legacy|Any CPU.ActiveCfg = Release Legacy|Any CPU 32 | {42445032-9098-4160-930D-4127DC292695}.Release Legacy|Any CPU.Build.0 = Release Legacy|Any CPU 33 | {42445032-9098-4160-930D-4127DC292695}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {42445032-9098-4160-930D-4127DC292695}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(ExtensibilityGlobals) = postSolution 40 | SolutionGuid = {CF2AE640-C05D-4B31-8048-8B40EC7CD7E4} 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/admin/personaBar/scripts/AzureAD.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | define(['jquery', 3 | 'main/config', 4 | 'main/loader' 5 | ], 6 | function ($, cf, loader) { 7 | var initCallback; 8 | var utility; 9 | var settings; 10 | var config = cf.init(); 11 | 12 | function loadScript(basePath) { 13 | var normalizedCulture = config.culture.split("-")[0]; 14 | var language = getBundleLanguage(normalizedCulture); 15 | var url = basePath + "/bundle-" + language + ".js"; 16 | $.ajax({ 17 | dataType: "script", 18 | cache: true, 19 | url: url 20 | }); 21 | } 22 | 23 | function getBundleLanguage(culture) { 24 | var fallbackLanguage = "en"; 25 | var availableLanguages = ["en"]; 26 | return availableLanguages.indexOf(culture) > 0 ? culture : fallbackLanguage; 27 | } 28 | 29 | 30 | return { 31 | init: function (wrapper, util, params, callback) { 32 | initCallback = callback; 33 | utility = util; 34 | settings = params.settings; 35 | 36 | if (!settings) { 37 | throw new Error("Azure AD settings are not defined in persona bar customSettings"); 38 | } 39 | 40 | var publicPath = settings.uiUrl + "/scripts/bundles/"; 41 | window.dnn.initAzureAD = function initializeAzureAD() { 42 | return { 43 | publicPath: publicPath, 44 | apiServiceUrl: settings.apiUrl, 45 | libraryVersion: settings.libraryVersion, 46 | loader: loader, 47 | utility: util, 48 | moduleName: 'AzureAD', 49 | notifier: { 50 | confirm: util.confirm, 51 | notify: util.notify, 52 | notifyError: util.notifyError 53 | } 54 | }; 55 | }; 56 | loadScript(publicPath); 57 | 58 | if (typeof callback === "function") { 59 | callback(); 60 | } 61 | }, 62 | 63 | load: function (params, callback) { 64 | var azureAD = window.dnn.azureAD; 65 | if (azureAD && azureAD.load) { 66 | azureAD.load(); 67 | } 68 | 69 | if (typeof callback === "function") { 70 | callback(); 71 | } 72 | } 73 | }; 74 | }); 75 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Services/AuthorizationController.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components; 2 | using DotNetNuke.Common; 3 | using DotNetNuke.Entities.Portals; 4 | using DotNetNuke.Web.Api; 5 | using System; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System.Web.Http; 10 | 11 | namespace DotNetNuke.Authentication.Azure.Services 12 | { 13 | public class AuthorizationController : DnnApiController 14 | { 15 | [HttpGet] 16 | [AllowAnonymous] 17 | public HttpResponseMessage RedirectToPortal() 18 | { 19 | try 20 | { 21 | var stateKey = Request.GetQueryNameValuePairs()?.FirstOrDefault(x => x.Key == "state"); 22 | if (stateKey == null) 23 | { 24 | return Request.CreateResponse(HttpStatusCode.BadRequest, "No state was specified"); 25 | } 26 | var state = new State(stateKey.Value.Value.ToString()); 27 | if (state.Service != AzureConfig.ServiceName) 28 | { 29 | return Request.CreateResponse(HttpStatusCode.BadRequest, "State not build for Azure AD"); 30 | } 31 | var portalId = state.PortalId; 32 | if (portalId < 0) 33 | { 34 | return Request.CreateResponse(HttpStatusCode.BadRequest, "Not valid portal Id"); 35 | } 36 | var portalAliases = PortalAliasController.Instance.GetPortalAliasesByPortalId(portalId).Where(x => x.IsPrimary); 37 | var portalAlias = portalAliases.FirstOrDefault(); 38 | if (!string.IsNullOrEmpty(state.Culture) && portalAliases.Any(x => x.CultureCode == state.Culture)) 39 | { 40 | portalAlias = portalAliases.FirstOrDefault(x => x.CultureCode == state.Culture); 41 | } 42 | 43 | var portalSettings = new PortalSettings(portalId); 44 | portalSettings.PortalAlias = portalAlias; 45 | var uriBuilder = new UriBuilder(Globals.LoginURL(state.RedirectUrl, false, portalSettings)); 46 | if (!Request.RequestUri.IsDefaultPort) 47 | { 48 | uriBuilder.Port = Request.RequestUri.Port; 49 | } 50 | uriBuilder.Query = !string.IsNullOrEmpty(Request.RequestUri.Query) ? Request.RequestUri.Query.Substring(1) : ""; 51 | 52 | var response = Request.CreateResponse(HttpStatusCode.Redirect); 53 | response.Headers.Location = uriBuilder.Uri; 54 | return response; 55 | } 56 | catch (Exception ex) 57 | { 58 | return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/MenuController.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2010-2017 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | using System.Collections.Generic; 25 | using Dnn.PersonaBar.Library.Controllers; 26 | using Dnn.PersonaBar.Library.Model; 27 | using DotNetNuke.Entities.Portals; 28 | using DotNetNuke.Entities.Users; 29 | 30 | namespace DotNetNuke.Authentication.Azure.Components 31 | { 32 | public class MenuController : IMenuItemController 33 | { 34 | public void UpdateParameters(MenuItem menuItem) 35 | { 36 | } 37 | 38 | public bool Visible(MenuItem menuItem) 39 | { 40 | var user = UserController.Instance.GetCurrentUserInfo(); 41 | return user != null && user.IsSuperUser; 42 | } 43 | 44 | public IDictionary GetSettings(MenuItem menuItem) 45 | { 46 | return PortalSettings.Current == null ? null : GetSettings(PortalSettings.Current.PortalId); 47 | } 48 | 49 | public IDictionary GetSettings(int portalId) 50 | { 51 | #if DEBUG 52 | var uiUrl = "http://localhost:8080/dist"; 53 | #else 54 | var uiUrl = "./Modules/Dnn.AzureAD"; 55 | #endif 56 | var apiUrl = "/DesktopModules/Admin/Dnn.PersonaBar/Modules/Dnn.AzureAD"; 57 | var version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); 58 | 59 | return new Dictionary 60 | { 61 | {"uiUrl", uiUrl}, 62 | {"apiUrl", apiUrl}, 63 | {"libraryVersion", version }, 64 | }; 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure.Extensibility/DotNetNuke.Authentication.Azure.Extensibility.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {42445032-9098-4160-930D-4127DC292695} 8 | Library 9 | Properties 10 | DotNetNuke.Authentication.Azure.Extensibility 11 | DotNetNuke.Authentication.Azure.Extensibility 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | bin\Release Legacy\ 35 | TRACE 36 | true 37 | pdbonly 38 | AnyCPU 39 | 7.3 40 | prompt 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/roleMappings/roleMappingRow/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .collapsible-component-item { 3 | display: block; 4 | float: left; 5 | width: 100%; 6 | cursor: auto; 7 | &:not(:last-child) { 8 | border-bottom: 1px solid @alto; 9 | } 10 | div.collapsible-item { 11 | width: 100%; 12 | float: left; 13 | position: relative; 14 | padding: 15px 0 10px 0; 15 | box-sizing: border-box; 16 | cursor: auto; 17 | .row { 18 | float: left; 19 | width: 100%; 20 | .item-row-dnnrole { 21 | width: 50%; 22 | float: left; 23 | padding-left: 15px; 24 | word-break: break-all; 25 | } 26 | .item-row-aadrole { 27 | width: 35%; 28 | float: left; 29 | white-space: nowrap; 30 | overflow: hidden; 31 | text-overflow: ellipsis; 32 | } 33 | .item-row-primary { 34 | width: 10%; 35 | float: left; 36 | text-align: center; 37 | .checkMarkIcon { 38 | width: 16px; 39 | height: 16px; 40 | margin-left: auto; 41 | margin-right: auto; 42 | > svg { 43 | fill: @thunder; 44 | } 45 | } 46 | } 47 | .item-row-actionButtons { 48 | width: 8%; 49 | margin-right: 15px; 50 | float: right; 51 | &:not(:last-child) { 52 | float: left; 53 | margin-right: 0px; 54 | } 55 | .delete-icon, .edit-icon { 56 | margin-left: 5px; 57 | float: right; 58 | display: block; 59 | cursor: pointer; 60 | > svg { 61 | width: 16px; 62 | float: left; 63 | height: 16px; 64 | &:hover { 65 | fill: @thunder; 66 | } 67 | fill: @alto; 68 | } 69 | } 70 | .delete-icon-hidden { 71 | display: none; 72 | } 73 | .edit-icon-active { 74 | > svg { 75 | width: 16px; 76 | float: right; 77 | height: 16px; 78 | fill: @curiousBlue; 79 | } 80 | } 81 | } 82 | .item-row-wrapper { 83 | padding: 0 5px 0 5px; 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/AzureUserData.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2019 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | #region Usings 25 | 26 | using System.Runtime.Serialization; 27 | using DotNetNuke.Entities.Users; 28 | using DotNetNuke.Services.Authentication.OAuth; 29 | 30 | #endregion 31 | 32 | namespace DotNetNuke.Authentication.Azure.Components 33 | { 34 | [DataContract] 35 | public class AzureUserData : UserData 36 | { 37 | #region Overrides 38 | 39 | public override string FirstName 40 | { 41 | get { return AzureFirstName; } 42 | set { } 43 | } 44 | 45 | public override string LastName 46 | { 47 | get { return AzureLastName; } 48 | set { } 49 | } 50 | 51 | public override string DisplayName 52 | { 53 | get { return AzureDisplayName; } 54 | set { } 55 | } 56 | 57 | #endregion 58 | 59 | [DataMember(Name = "given_name")] 60 | public string AzureFirstName { get; set; } 61 | 62 | [DataMember(Name = "family_name")] 63 | public string AzureLastName { get; set; } 64 | 65 | [DataMember(Name = "name")] 66 | public string AzureDisplayName { get; set; } 67 | 68 | public UserInfo ToUserInfo(bool usernamePrefixEnabled) 69 | { 70 | return new UserInfo() 71 | { 72 | DisplayName = this.DisplayName, 73 | FirstName = this.FirstName, 74 | LastName = this.LastName, 75 | Email = this.Email, 76 | Username = usernamePrefixEnabled ? $"Azure-{this.Id}" : this.Id 77 | }; 78 | } 79 | 80 | 81 | } 82 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/userMappingRow/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .collapsible-component-item { 3 | display: block; 4 | float: left; 5 | width: 100%; 6 | cursor: auto; 7 | &:not(:last-child) { 8 | border-bottom: 1px solid @alto; 9 | } 10 | div.collapsible-item { 11 | width: 100%; 12 | float: left; 13 | position: relative; 14 | padding: 15px 0 10px 0; 15 | box-sizing: border-box; 16 | cursor: auto; 17 | .row { 18 | float: left; 19 | width: 100%; 20 | .item-row-dnnproperty { 21 | width: 50%; 22 | float: left; 23 | padding-left: 15px; 24 | word-break: break-all; 25 | } 26 | .item-row-aadproperty { 27 | width: 37%; 28 | float: left; 29 | white-space: nowrap; 30 | overflow: hidden; 31 | text-overflow: ellipsis; 32 | } 33 | .item-row-primary { 34 | width: 10%; 35 | float: left; 36 | text-align: center; 37 | .checkMarkIcon { 38 | width: 16px; 39 | height: 16px; 40 | margin-left: auto; 41 | margin-right: auto; 42 | > svg { 43 | fill: @thunder; 44 | } 45 | } 46 | } 47 | .item-row-actionButtons { 48 | width: 8%; 49 | margin-right: 15px; 50 | float: right; 51 | &:not(:last-child) { 52 | float: left; 53 | margin-right: 0px; 54 | } 55 | .delete-icon, .edit-icon { 56 | margin-left: 5px; 57 | float: right; 58 | display: block; 59 | cursor: pointer; 60 | > svg { 61 | width: 16px; 62 | float: left; 63 | height: 16px; 64 | &:hover { 65 | fill: @thunder; 66 | } 67 | fill: @alto; 68 | } 69 | } 70 | .delete-icon-hidden { 71 | display: none; 72 | } 73 | .edit-icon-active { 74 | > svg { 75 | width: 16px; 76 | float: right; 77 | height: 16px; 78 | fill: @curiousBlue; 79 | } 80 | } 81 | } 82 | .item-row-wrapper { 83 | padding: 0 5px 0 5px; 84 | } 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/roleMappings/roleMappingRow/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Collapsible, SvgIcons } from "@dnnsoftware/dnn-react-common"; 4 | import "./style.less"; 5 | 6 | class RoleMappingRow extends Component { 7 | /* eslint-disable react/no-did-mount-set-state */ 8 | componentDidMount() { 9 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 10 | this.setState({ 11 | opened 12 | }); 13 | } 14 | 15 | toggle() { 16 | if ((this.props.openId !== "" && this.props.id === this.props.openId)) { 17 | this.props.Collapse(); 18 | } 19 | else { 20 | this.props.OpenCollapse(this.props.id); 21 | } 22 | } 23 | 24 | /* eslint-disable react/no-danger */ 25 | render() { 26 | const {props} = this; 27 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 28 | return ( 29 |
    30 |
    31 |
    32 |
    33 | {props.dnnRoleName}
    34 |
    35 | {props.aadRoleName}
    36 |
    37 | {props.deletable && 38 |
    39 | } 40 | {props.editable && 41 |
    42 | } 43 |
    44 |
    45 |
    46 | {opened && props.children} 47 |
    48 | ); 49 | } 50 | } 51 | 52 | RoleMappingRow.propTypes = { 53 | mappingId: PropTypes.string, 54 | dnnRoleName: PropTypes.string, 55 | aadRoleName: PropTypes.string, 56 | deletable: PropTypes.bool, 57 | editable: PropTypes.bool, 58 | OpenCollapse: PropTypes.func, 59 | Collapse: PropTypes.func, 60 | onDelete: PropTypes.func, 61 | id: PropTypes.string, 62 | openId: PropTypes.string 63 | }; 64 | 65 | RoleMappingRow.defaultProps = { 66 | collapsed: true, 67 | deletable: true, 68 | editable: true 69 | }; 70 | export default (RoleMappingRow); 71 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/userMappingRow/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Collapsible, SvgIcons } from "@dnnsoftware/dnn-react-common"; 4 | import "./style.less"; 5 | 6 | class UserMappingRow extends Component { 7 | /* eslint-disable react/no-did-mount-set-state */ 8 | componentDidMount() { 9 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 10 | this.setState({ 11 | opened 12 | }); 13 | } 14 | 15 | toggle() { 16 | if ((this.props.openId !== "" && this.props.id === this.props.openId)) { 17 | this.props.Collapse(); 18 | } 19 | else { 20 | this.props.OpenCollapse(this.props.id); 21 | } 22 | } 23 | 24 | /* eslint-disable react/no-danger */ 25 | render() { 26 | const {props} = this; 27 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 28 | return ( 29 |
    30 |
    31 |
    32 |
    33 | {props.dnnPropertyName}
    34 |
    35 | {props.aadClaimName}
    36 |
    37 | {props.deletable && 38 |
    39 | } 40 | {props.editable && 41 |
    42 | } 43 |
    44 |
    45 |
    46 | {opened && props.children} 47 |
    48 | ); 49 | } 50 | } 51 | 52 | UserMappingRow.propTypes = { 53 | mappingId: PropTypes.string, 54 | dnnPropertyName: PropTypes.string, 55 | aadClaimName: PropTypes.string, 56 | deletable: PropTypes.bool, 57 | editable: PropTypes.bool, 58 | OpenCollapse: PropTypes.func, 59 | Collapse: PropTypes.func, 60 | onDelete: PropTypes.func, 61 | id: PropTypes.string, 62 | openId: PropTypes.string 63 | }; 64 | 65 | UserMappingRow.defaultProps = { 66 | collapsed: true, 67 | deletable: false, 68 | editable: true 69 | }; 70 | export default (UserMappingRow); 71 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/profileMappings/profileMappingRow/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index.less"; 2 | .collapsible-component-profile { 3 | display: block; 4 | float: left; 5 | width: 100%; 6 | cursor: auto; 7 | &:not(:last-child) { 8 | border-bottom: 1px solid @alto; 9 | } 10 | div.collapsible-profile { 11 | width: 100%; 12 | float: left; 13 | position: relative; 14 | padding: 15px 0 10px 0; 15 | box-sizing: border-box; 16 | cursor: auto; 17 | .row { 18 | float: left; 19 | width: 100%; 20 | .item-row-dnnprofile { 21 | width: 35%; 22 | float: left; 23 | padding-left: 15px; 24 | word-break: break-all; 25 | } 26 | .item-row-aadprofile { 27 | width: 20%; 28 | float: left; 29 | } 30 | .item-row-aadextension { 31 | width: 30%; 32 | float: left; 33 | white-space: nowrap; 34 | overflow: hidden; 35 | text-overflow: ellipsis; 36 | } 37 | .item-row-primary { 38 | width: 10%; 39 | float: left; 40 | text-align: center; 41 | .checkMarkIcon { 42 | width: 16px; 43 | height: 16px; 44 | margin-left: auto; 45 | margin-right: auto; 46 | > svg { 47 | fill: @thunder; 48 | } 49 | } 50 | } 51 | .item-row-actionButtons { 52 | width: 8%; 53 | margin-right: 15px; 54 | float: right; 55 | &:not(:last-child) { 56 | float: left; 57 | margin-right: 0px; 58 | } 59 | .delete-icon, .edit-icon { 60 | margin-left: 5px; 61 | float: right; 62 | display: block; 63 | cursor: pointer; 64 | > svg { 65 | width: 16px; 66 | float: left; 67 | height: 16px; 68 | &:hover { 69 | fill: @thunder; 70 | } 71 | fill: @alto; 72 | } 73 | } 74 | .delete-icon-hidden { 75 | display: none; 76 | } 77 | .edit-icon-active { 78 | > svg { 79 | width: 16px; 80 | float: right; 81 | height: 16px; 82 | fill: @curiousBlue; 83 | } 84 | } 85 | } 86 | .item-row-wrapper { 87 | padding: 0 5px 0 5px; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/profileMappings/profileMappingRow/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Collapsible, SvgIcons } from "@dnnsoftware/dnn-react-common"; 4 | import "./style.less"; 5 | 6 | class ProfileMappingRow extends Component { 7 | /* eslint-disable react/no-did-mount-set-state */ 8 | componentDidMount() { 9 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 10 | this.setState({ 11 | opened 12 | }); 13 | } 14 | 15 | toggle() { 16 | if ((this.props.openId !== "" && this.props.id === this.props.openId)) { 17 | this.props.Collapse(); 18 | } 19 | else { 20 | this.props.OpenCollapse(this.props.id); 21 | } 22 | } 23 | 24 | /* eslint-disable react/no-danger */ 25 | render() { 26 | const {props} = this; 27 | let opened = (this.props.openId !== "" && this.props.id === this.props.openId); 28 | return ( 29 |
    30 |
    31 |
    32 |
    33 | {props.dnnProfilePropertyName}
    34 |
    35 | {props.aadClaimName}
    36 |
    37 | {props.deletable && 38 |
    39 | } 40 | {props.editable && 41 |
    42 | } 43 |
    44 |
    45 |
    46 | {opened && props.children} 47 |
    48 | ); 49 | } 50 | } 51 | 52 | ProfileMappingRow.propTypes = { 53 | profileMappingId: PropTypes.string, 54 | dnnProfilePropertyName: PropTypes.string, 55 | aadClaimName: PropTypes.string, 56 | deletable: PropTypes.bool, 57 | editable: PropTypes.bool, 58 | OpenCollapse: PropTypes.func, 59 | Collapse: PropTypes.func, 60 | onDelete: PropTypes.func, 61 | id: PropTypes.string, 62 | openId: PropTypes.string 63 | }; 64 | 65 | ProfileMappingRow.defaultProps = { 66 | collapsed: true, 67 | deletable: true, 68 | editable: true 69 | }; 70 | export default (ProfileMappingRow); 71 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/roleMappings/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index"; 2 | .dnn-azuread-aad-roleMappingSettings { 3 | .items { 4 | margin: 30px 30px; 5 | width: 738px; 6 | float: left; 7 | box-sizing: border-box; 8 | .items-grid { 9 | border: solid 1px @alto; 10 | float: left; 11 | width: 100%; 12 | } 13 | .header-row { 14 | border-bottom: 1px solid @alto; 15 | padding: 10px 0 10px 0; 16 | width: 100%; 17 | float: left; 18 | overflow: hidden; 19 | } 20 | .header-DnnRole { 21 | width: 50%; 22 | float: left; 23 | font-weight: bolder; 24 | padding-left: 15px; 25 | } 26 | .header-AadRole { 27 | width: 20%; 28 | float: left; 29 | font-weight: bolder; 30 | } 31 | .collapsible-component { 32 | .collapsible-header { 33 | text-align: right; 34 | text-transform: none; 35 | padding-right: 40px; 36 | .collapse-icon { 37 | display: none; 38 | &.collapsed { 39 | display: none; 40 | } 41 | } 42 | } 43 | } 44 | .AddItemRow { 45 | text-align: right; 46 | width: 100%; 47 | float: right; 48 | margin: 0 0 15px 0; 49 | font-weight: bolder; 50 | border-bottom: 1px solid @alto; 51 | overflow: hidden; 52 | height: 25px; 53 | .sectionTitle { 54 | font-weight: bolder; 55 | float: left; 56 | } 57 | .AddItemBox { 58 | width: auto; 59 | float: right; 60 | color: @thunder; 61 | cursor: pointer; 62 | .add-icon { 63 | margin-left: 20px; 64 | margin-right: 5px; 65 | float: left; 66 | cursor: pointer; 67 | svg { 68 | width: 16px; 69 | float: left; 70 | height: 16px; 71 | fill: @thunder; 72 | } 73 | } 74 | } 75 | .AddItemBox-active { 76 | width: auto; 77 | float: right; 78 | color: @curiousBlue; 79 | .add-icon { 80 | margin-left: 20px; 81 | margin-right: 5px; 82 | float: left; 83 | svg { 84 | width: 16px; 85 | float: left; 86 | height: 16px; 87 | fill: @curiousBlue; 88 | } 89 | } 90 | } 91 | } 92 | .role-item { 93 | color: @thunder; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index"; 2 | .dnn-azuread-aad-userMappingSettings { 3 | .items { 4 | margin: 30px 30px; 5 | width: 738px; 6 | float: left; 7 | box-sizing: border-box; 8 | .items-grid { 9 | border: solid 1px @alto; 10 | float: left; 11 | width: 100%; 12 | } 13 | .header-row { 14 | border-bottom: 1px solid @alto; 15 | padding: 10px 0 10px 0; 16 | width: 100%; 17 | float: left; 18 | overflow: hidden; 19 | } 20 | .header-DnnProperty { 21 | width: 50%; 22 | float: left; 23 | font-weight: bolder; 24 | padding-left: 15px; 25 | } 26 | .header-AadProperty { 27 | width: 20%; 28 | float: left; 29 | font-weight: bolder; 30 | } 31 | .collapsible-component { 32 | .collapsible-header { 33 | text-align: right; 34 | text-transform: none; 35 | padding-right: 40px; 36 | .collapse-icon { 37 | display: none; 38 | &.collapsed { 39 | display: none; 40 | } 41 | } 42 | } 43 | } 44 | .AddItemRow { 45 | text-align: right; 46 | width: 100%; 47 | float: right; 48 | margin: 0 0 15px 0; 49 | font-weight: bolder; 50 | border-bottom: 1px solid @alto; 51 | overflow: hidden; 52 | height: 25px; 53 | .sectionTitle { 54 | font-weight: bolder; 55 | float: left; 56 | } 57 | .AddItemBox { 58 | width: auto; 59 | float: right; 60 | color: @thunder; 61 | cursor: pointer; 62 | .add-icon { 63 | margin-left: 20px; 64 | margin-right: 5px; 65 | float: left; 66 | cursor: pointer; 67 | svg { 68 | width: 16px; 69 | float: left; 70 | height: 16px; 71 | fill: @thunder; 72 | } 73 | } 74 | } 75 | .AddItemBox-active { 76 | width: auto; 77 | float: right; 78 | color: @curiousBlue; 79 | .add-icon { 80 | margin-left: 20px; 81 | margin-right: 5px; 82 | float: left; 83 | svg { 84 | width: 16px; 85 | float: left; 86 | height: 16px; 87 | fill: @curiousBlue; 88 | } 89 | } 90 | } 91 | } 92 | .role-item { 93 | color: @thunder; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/profileMappings/style.less: -------------------------------------------------------------------------------- 1 | @import "~@dnnsoftware/dnn-react-common/styles/index"; 2 | .dnn-azuread-aad-profileMappingSettings { 3 | .profile-items { 4 | margin: 30px 30px; 5 | width: 738px; 6 | float: left; 7 | box-sizing: border-box; 8 | .profile-items-grid { 9 | border: solid 1px @alto; 10 | float: left; 11 | width: 100%; 12 | } 13 | .header-row { 14 | border-bottom: 1px solid @alto; 15 | padding: 10px 0 10px 0; 16 | width: 100%; 17 | float: left; 18 | overflow: hidden; 19 | } 20 | .header-DnnProfileProperty { 21 | width: 35%; 22 | float: left; 23 | font-weight: bolder; 24 | padding-left: 15px; 25 | } 26 | .header-AadClaim { 27 | width: 40%; 28 | float: left; 29 | font-weight: bolder; 30 | } 31 | .collapsible-component { 32 | .collapsible-header { 33 | text-align: right; 34 | text-transform: none; 35 | padding-right: 40px; 36 | .collapse-icon { 37 | display: none; 38 | &.collapsed { 39 | display: none; 40 | } 41 | } 42 | } 43 | } 44 | .AddItemRow { 45 | text-align: right; 46 | width: 100%; 47 | float: right; 48 | margin: 0 0 15px 0; 49 | font-weight: bolder; 50 | border-bottom: 1px solid @alto; 51 | overflow: hidden; 52 | height: 25px; 53 | .sectionTitle { 54 | font-weight: bolder; 55 | float: left; 56 | } 57 | .AddItemBox { 58 | width: auto; 59 | float: right; 60 | color: @thunder; 61 | cursor: pointer; 62 | .add-icon { 63 | margin-left: 20px; 64 | margin-right: 5px; 65 | float: left; 66 | cursor: pointer; 67 | svg { 68 | width: 16px; 69 | float: left; 70 | height: 16px; 71 | fill: @thunder; 72 | } 73 | } 74 | } 75 | .AddItemBox-active { 76 | width: auto; 77 | float: right; 78 | color: @curiousBlue; 79 | .add-icon { 80 | margin-left: 20px; 81 | margin-right: 5px; 82 | float: left; 83 | svg { 84 | width: 16px; 85 | float: left; 86 | height: 16px; 87 | fill: @curiousBlue; 88 | } 89 | } 90 | } 91 | } 92 | .profile-item { 93 | color: @thunder; 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/services/applicationService.js: -------------------------------------------------------------------------------- 1 | import util from "../utils"; 2 | class ApplicationService { 3 | getServiceFramework(controller) { 4 | let sf = util.utilities.sf; 5 | sf.controller = controller; 6 | return sf; 7 | } 8 | 9 | getSettings(callback) { 10 | const sf = this.getServiceFramework("AzureAD"); 11 | sf.get("GetSettings", {}, callback); 12 | } 13 | 14 | updateGeneralSettings(payload, callback, failureCallback) { 15 | const sf = this.getServiceFramework("AzureAD"); 16 | sf.post("UpdateGeneralSettings", payload, callback, failureCallback); 17 | } 18 | 19 | updateAdvancedSyncSettings(payload, callback, failureCallback) { 20 | const sf = this.getServiceFramework("AzureAD"); 21 | sf.post("UpdateAdvancedSyncSettings", payload, callback, failureCallback); 22 | } 23 | 24 | updateAdvancedMoreSettings(payload, callback, failureCallback) { 25 | const sf = this.getServiceFramework("AzureAD"); 26 | sf.post("UpdateAdvancedMoreSettings", payload, callback, failureCallback); 27 | } 28 | 29 | updateProfileMapping(payload, callback, failureCallback) { 30 | const sf = this.getServiceFramework("AzureAD"); 31 | sf.post("UpdateProfileMapping", payload, callback, failureCallback); 32 | } 33 | 34 | deleteProfileMapping(payload, callback, failureCallback) { 35 | const sf = this.getServiceFramework("AzureAD"); 36 | sf.post("DeleteProfileMapping", payload, callback, failureCallback); 37 | } 38 | getProfileSettings(callback) { 39 | const sf = this.getServiceFramework("AzureAD"); 40 | sf.get("GetProfileSettings", {}, callback); 41 | } 42 | 43 | getProfileProperties(callback) { 44 | const sf = this.getServiceFramework("AzureAD"); 45 | sf.get("GetProfileProperties", {}, callback); 46 | } 47 | 48 | getRoleMappingSettings(callback) { 49 | const sf = this.getServiceFramework("AzureAD"); 50 | sf.get("GetRoleMappingSettings", {}, callback); 51 | } 52 | 53 | getAvailableRoles(callback) { 54 | const sf = this.getServiceFramework("AzureAD"); 55 | sf.get("GetAvailableRoles", {}, callback); 56 | } 57 | 58 | updateRoleMapping(payload, callback, failureCallback) { 59 | const sf = this.getServiceFramework("AzureAD"); 60 | sf.post("UpdateRoleMapping", payload, callback, failureCallback); 61 | } 62 | 63 | deleteRoleMapping(payload, callback, failureCallback) { 64 | const sf = this.getServiceFramework("AzureAD"); 65 | sf.post("DeleteRoleMapping", payload, callback, failureCallback); 66 | } 67 | 68 | getUserMappingSettings(callback) { 69 | const sf = this.getServiceFramework("AzureAD"); 70 | sf.get("GetUserMappingSettings", {}, callback); 71 | } 72 | 73 | updateUserMapping(payload, callback, failureCallback) { 74 | const sf = this.getServiceFramework("AzureAD"); 75 | sf.post("UpdateUserMapping", payload, callback, failureCallback); 76 | } 77 | 78 | } 79 | const applicationService = new ApplicationService(); 80 | export default applicationService; -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/App.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from "react"; 2 | import PropTypes from "prop-types"; 3 | import { connect } from "react-redux"; 4 | import {PersonaBarPage, PersonaBarPageHeader, PersonaBarPageBody, DnnTabs as Tabs} from "@dnnsoftware/dnn-react-common"; 5 | import SettingsActions from "../actions/settings"; 6 | import GeneralSettings from "./general"; 7 | import SyncSettings from "./advanced/sync"; 8 | import MoreSettings from "./advanced/more"; 9 | import ProfileMappings from "./profileMappings"; 10 | import UserMappings from "./userMappings"; 11 | import RoleMappings from "./roleMappings"; 12 | import resx from "../resources"; 13 | 14 | import "./style.less"; 15 | 16 | class App extends Component { 17 | 18 | constructor() { 19 | super(); 20 | 21 | } 22 | onSelectTab(index) { 23 | this.props.dispatch(SettingsActions.switchTab(index)); 24 | } 25 | onSelectSubTab(index) { 26 | this.props.dispatch(SettingsActions.switchMappingSubTab(index)); 27 | } 28 | render() { 29 | return ( 30 |
    31 | 32 | 33 | 34 | 35 | 39 | 40 | 46 | 47 | 48 | 49 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 | ); 65 | } 66 | } 67 | 68 | App.propTypes = { 69 | dispatch: PropTypes.func.isRequired, 70 | selectedTab: PropTypes.number, 71 | selectedMappingSubTab: PropTypes.number 72 | }; 73 | 74 | 75 | function mapStateToProps(state) { 76 | return { 77 | selectedTab: state.settings.selectedTab, 78 | selectedMappingSubTab: state.settings.selectedMappingSubTab 79 | }; 80 | } 81 | 82 | export default connect(mapStateToProps)(App); -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/UserMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using DotNetNuke.Common; 3 | using DotNetNuke.Data; 4 | using DotNetNuke.Entities.Users; 5 | using DotNetNuke.Framework; 6 | using System; 7 | using System.Linq; 8 | 9 | namespace DotNetNuke.Authentication.Azure.Data 10 | { 11 | public class UserMappingsRepository : ServiceLocator, IUserMappingsRepository 12 | { 13 | protected override Func GetFactory() 14 | { 15 | return () => new UserMappingsRepository(); 16 | } 17 | 18 | public IQueryable GetUserMappings(int portalId) 19 | { 20 | IQueryable result = null; 21 | 22 | using (IDataContext ctx = DataContext.Instance()) 23 | { 24 | var rep = ctx.GetRepository(); 25 | result = rep.Find("WHERE PortalId = @0", portalId).AsQueryable(); 26 | } 27 | 28 | return result; 29 | } 30 | 31 | public UserMapping GetUserMapping(string dnnPropertyName, int portalId) 32 | { 33 | Requires.NotNullOrEmpty("DnnPropertyName", dnnPropertyName); 34 | 35 | UserMapping result; 36 | using (IDataContext ctx = DataContext.Instance()) 37 | { 38 | var rep = ctx.GetRepository(); 39 | result = rep.Find("WHERE DnnPropertyName = @0 AND PortalId = @1", dnnPropertyName, portalId).FirstOrDefault(); 40 | } 41 | return result; 42 | } 43 | 44 | public void UpdateUserMapping(string dnnPropertyName, string aadClaimName, int portalId) 45 | { 46 | Requires.NotNullOrEmpty("DnnPropertyName", dnnPropertyName); 47 | 48 | var userMapping = GetUserMapping(dnnPropertyName, portalId); 49 | if (userMapping == null) 50 | { 51 | throw new ArgumentException($"User mapping '{dnnPropertyName}' not found in portal {portalId}"); 52 | } 53 | 54 | userMapping.AadClaimName = aadClaimName; 55 | userMapping.PortalId = portalId; 56 | userMapping.LastModifiedOnDate = DateTime.UtcNow; 57 | userMapping.LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID; 58 | using (IDataContext ctx = DataContext.Instance()) 59 | { 60 | var rep = ctx.GetRepository(); 61 | rep.Update(userMapping); 62 | } 63 | } 64 | 65 | public void InsertUserMapping(string dnnPropertyName, string aadClaimName, int portalId) 66 | { 67 | Requires.NotNullOrEmpty("DnnPropertyName", dnnPropertyName); 68 | Requires.NotNullOrEmpty("AadClaimName", aadClaimName); 69 | 70 | var userMapping = new UserMapping 71 | { 72 | DnnPropertyName = dnnPropertyName, 73 | CreatedByUserId = UserController.Instance.GetCurrentUserInfo().UserID, 74 | CreatedOnDate = DateTime.UtcNow, 75 | AadClaimName = aadClaimName, 76 | PortalId = portalId, 77 | LastModifiedOnDate = DateTime.UtcNow, 78 | LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID 79 | }; 80 | using (IDataContext ctx = DataContext.Instance()) 81 | { 82 | var rep = ctx.GetRepository(); 83 | rep.Insert(userMapping); 84 | } 85 | 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Auth/AadAuthMessageHandler.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2020 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | #region Usings 25 | using DotNetNuke.Authentication.Azure.Components; 26 | using DotNetNuke.Instrumentation; 27 | using DotNetNuke.Web.Api.Auth; 28 | using System; 29 | using System.Net.Http; 30 | using System.Security.Principal; 31 | using System.Threading; 32 | #endregion 33 | 34 | namespace DotNetNuke.Authentication.Azure.Auth 35 | { 36 | /// 37 | /// This class implements Azure AD authentication using JWT scheme 38 | /// 39 | public class AadAuthMessageHandler : AuthMessageHandlerBase 40 | { 41 | #region constants, properties, etc. 42 | private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(AadAuthMessageHandler)); 43 | private readonly IAadController _b2cController = AadController.Instance; 44 | public override string AuthScheme => _b2cController.SchemeType; 45 | public override bool BypassAntiForgeryToken => true; 46 | internal static bool IsEnabled { get; set; } 47 | #endregion 48 | 49 | #region constructor 50 | public AadAuthMessageHandler(bool includeByDefault, bool forceSsl) 51 | : base(includeByDefault, forceSsl) 52 | { 53 | // Once an instance is enabled and gets registered in 54 | // ServicesRoutingManager.RegisterAuthenticationHandlers() 55 | // this scheme gets marked as enabled. 56 | IsEnabled = true; 57 | } 58 | 59 | #endregion 60 | 61 | #region implementation 62 | 63 | public override HttpResponseMessage OnInboundRequest(HttpRequestMessage request, CancellationToken cancellationToken) 64 | { 65 | if (NeedsAuthentication(request)) 66 | { 67 | TryToAuthenticate(request); 68 | } 69 | return base.OnInboundRequest(request, cancellationToken); 70 | } 71 | 72 | private void TryToAuthenticate(HttpRequestMessage request) 73 | { 74 | try 75 | { 76 | var username = _b2cController.ValidateToken(request); 77 | if (!string.IsNullOrEmpty(username)) 78 | { 79 | if (Logger.IsDebugEnabled) Logger.Debug($"Authenticated user '{username}'"); 80 | SetCurrentPrincipal(new GenericPrincipal(new GenericIdentity(username, AuthScheme), null), request); 81 | } 82 | } 83 | catch (Exception ex) 84 | { 85 | Logger.Error("Unexpected error in authenticating the user. " + ex); 86 | } 87 | } 88 | 89 | #endregion 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | *.csproj.user 9 | 10 | # Build results 11 | [Dd]ebug/ 12 | [Dd]ebugPublic/ 13 | [Rr]elease/ 14 | [Rr]eleases/ 15 | [Pp]roduction/ 16 | [Qq][Aa]/ 17 | 18 | x64/ 19 | build/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | 24 | # Roslyn cache directories 25 | *.ide/ 26 | 27 | # MSTest test Results 28 | [Tt]est[Rr]esult*/ 29 | [Bb]uild[Ll]og.* 30 | 31 | #NUNIT 32 | *.VisualState.xml 33 | TestResult.xml 34 | 35 | # Build Results of an ATL Project 36 | [Dd]ebugPS/ 37 | [Rr]eleasePS/ 38 | dlldata.c 39 | 40 | *_i.c 41 | *_p.c 42 | *_i.h 43 | *.ilk 44 | *.meta 45 | *.obj 46 | *.pch 47 | *.pdb 48 | *.pgc 49 | *.pgd 50 | *.rsp 51 | *.sbr 52 | *.tlb 53 | *.tli 54 | *.tlh 55 | *.tmp 56 | *.tmp_proj 57 | *.log 58 | *.vspscc 59 | *.vssscc 60 | .builds 61 | *.pidb 62 | *.svclog 63 | *.scc 64 | 65 | # Chutzpah Test files 66 | _Chutzpah* 67 | 68 | # Visual C++ cache files 69 | ipch/ 70 | *.aps 71 | *.ncb 72 | *.opensdf 73 | *.sdf 74 | *.cachefile 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | *.vspx 80 | 81 | # TFS 2012 Local Workspace 82 | $tf/ 83 | 84 | # Guidance Automation Toolkit 85 | *.gpState 86 | 87 | # ReSharper is a .NET coding add-in 88 | _ReSharper*/ 89 | *.[Rr]e[Ss]harper 90 | *.DotSettings.user 91 | 92 | # JustCode is a .NET coding addin-in 93 | .JustCode 94 | 95 | # TeamCity is a build add-in 96 | _TeamCity* 97 | 98 | # DotCover is a Code Coverage Tool 99 | *.dotCover 100 | 101 | # NCrunch 102 | _NCrunch_* 103 | .*crunch*.local.xml 104 | 105 | # MightyMoose 106 | *.mm.* 107 | AutoTest.Net/ 108 | 109 | # Web workbench (sass) 110 | .sass-cache/ 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.[Pp]ublish.xml 130 | *.azurePubxml 131 | ## TODO: Comment the next line if you want to checkin your 132 | ## web deploy settings but do note that will include unencrypted 133 | ## passwords 134 | *.pubxml 135 | 136 | # NuGet Packages Directory 137 | packages/* 138 | ## TODO: If the tool you use requires repositories.config 139 | ## uncomment the next line 140 | #!packages/repositories.config 141 | 142 | # Enable "build/" folder in the NuGet Packages folder since 143 | # NuGet packages use it for MSBuild targets. 144 | # This line needs to be after the ignore of the build folder 145 | # (and the packages folder if the line above has been uncommented) 146 | !packages/build/ 147 | 148 | # Windows Azure Build Output 149 | csx/ 150 | *.build.csdef 151 | 152 | # Windows Store app package directory 153 | AppPackages/ 154 | 155 | # Others 156 | sql/ 157 | *.Cache 158 | ClientBin/ 159 | [Ss]tyle[Cc]op.* 160 | ~$* 161 | *~ 162 | *.dbmdl 163 | *.dbproj.schemaview 164 | *.pfx 165 | *.publishsettings 166 | node_modules/ 167 | 168 | # RIA/Silverlight projects 169 | Generated_Code/ 170 | 171 | # Backup & report files from converting an old project file 172 | # to a newer Visual Studio version. Backup files are not needed, 173 | # because we have git ;-) 174 | _UpgradeReport_Files/ 175 | Backup*/ 176 | UpgradeLog*.XML 177 | UpgradeLog*.htm 178 | 179 | # SQL Server files 180 | *.mdf 181 | *.ldf 182 | 183 | # Business Intelligence projects 184 | *.rdl.data 185 | *.bim.layout 186 | *.bim_*.settings 187 | 188 | # Microsoft Fakes 189 | FakesAssemblies/ 190 | 191 | ############ 192 | ## Windows 193 | ############ 194 | 195 | # Windows image file caches 196 | [Tt]humbs.db 197 | 198 | # Folder config file 199 | [Dd]esktop.ini 200 | 201 | .vs/ 202 | /DotNetNuke.Authentication.Azure/packages 203 | /Releases 204 | /DotNetNuke.Authentication.Azure/AzureAD.Web/package-lock.json 205 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const packageJson = require("./package.json"); 3 | const path = require("path"); 4 | const isProduction = process.env.NODE_ENV === "production"; 5 | const languages = { 6 | "en": null 7 | // TODO: create locallizaton files per language 8 | // "de": require("./localizations/de.json"), 9 | // "es": require("./localizations/es.json"), 10 | // "fr": require("./localizations/fr.json"), 11 | // "it": require("./localizations/it.json"), 12 | // "nl": require("./localizations/nl.json") 13 | }; 14 | 15 | const webpackExternals = require("@dnnsoftware/dnn-react-common/WebpackExternals"); 16 | 17 | module.exports = (env, argv) => { 18 | const isProduction = argv.mode === "production"; 19 | return { 20 | entry: "./src/main.jsx", 21 | optimization: { 22 | minimize: isProduction 23 | }, 24 | output: { 25 | path: path.resolve(__dirname, "../admin/personaBar/scripts/bundles/"), 26 | filename: "bundle-en.js", 27 | publicPath: isProduction ? "" : "http://localhost:8080/dist/scripts/bundles" 28 | }, 29 | devServer: { 30 | allowedHosts: "all" 31 | }, 32 | resolve: { 33 | extensions: ["*", ".js", ".json", ".jsx"], 34 | modules: [ 35 | path.resolve('./src'), // Look in src first 36 | path.resolve('./node_modules') // Try local node_modules 37 | ] 38 | }, 39 | 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.(js|jsx)$/, 44 | exclude: /node_modules/, 45 | enforce: "pre", 46 | loader: "eslint-loader", 47 | options: { 48 | fix: true, 49 | }, 50 | }, 51 | { 52 | test: /\.less$/, 53 | use: [{ 54 | loader: 'style-loader' // creates style nodes from JS strings 55 | }, { 56 | loader: 'css-loader', // translates CSS into CommonJS 57 | options: { modules: "global" } 58 | }, { 59 | loader: 'less-loader' // compiles Less to CSS 60 | }] 61 | }, 62 | { 63 | test: /\.(js|jsx)$/, 64 | exclude: /node_modules/, 65 | use: { 66 | loader: 'babel-loader', 67 | options: { 68 | presets: ['@babel/preset-env','@babel/preset-react'] 69 | } 70 | } 71 | }, 72 | { 73 | test: /\.(ttf|woff)$/, 74 | use: { 75 | loader: 'url-loader?limit=8192' 76 | } 77 | }, 78 | { 79 | test: /\.(gif|png)$/, 80 | loader: "url-loader?mimetype=image/png" 81 | } 82 | ] 83 | }, 84 | externals: webpackExternals, 85 | 86 | plugins: isProduction 87 | ? [ 88 | new webpack.DefinePlugin({ 89 | VERSION: JSON.stringify(packageJson.version), 90 | "process.env": { 91 | NODE_ENV: JSON.stringify("production") 92 | } 93 | }) 94 | ] 95 | : [ 96 | new webpack.DefinePlugin({ 97 | VERSION: JSON.stringify(packageJson.version), 98 | "process.env": { 99 | NODE_ENV: JSON.stringify("development") 100 | } 101 | }) 102 | ], 103 | }; 104 | }; 105 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/RoleMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using DotNetNuke.Common; 3 | using DotNetNuke.Data; 4 | using DotNetNuke.Entities.Users; 5 | using DotNetNuke.Framework; 6 | using System; 7 | using System.Linq; 8 | 9 | namespace DotNetNuke.Authentication.Azure.Data 10 | { 11 | public class RoleMappingsRepository : ServiceLocator, IRoleMappingsRepository 12 | { 13 | protected override Func GetFactory() 14 | { 15 | return () => new RoleMappingsRepository(); 16 | } 17 | 18 | public IQueryable GetRoleMappings(int portalId) 19 | { 20 | IQueryable result = null; 21 | 22 | using (IDataContext ctx = DataContext.Instance()) 23 | { 24 | var rep = ctx.GetRepository(); 25 | result = rep.Find("WHERE PortalId = @0", portalId).AsQueryable(); 26 | } 27 | 28 | return result; 29 | } 30 | 31 | public RoleMapping GetRoleMapping(string dnnRoleName, int portalId) 32 | { 33 | Requires.NotNullOrEmpty("DnnRoleName", dnnRoleName); 34 | 35 | RoleMapping result; 36 | using (IDataContext ctx = DataContext.Instance()) 37 | { 38 | var rep = ctx.GetRepository(); 39 | result = rep.Find("WHERE DnnRoleName = @0 AND PortalId = @1", dnnRoleName, portalId).FirstOrDefault(); 40 | } 41 | return result; 42 | } 43 | 44 | public void UpdateRoleMapping(string originalDnnRoleName, string dnnRoleName, string aadRoleName, int portalId) 45 | { 46 | Requires.NotNullOrEmpty("OriginalDnnRoleName", originalDnnRoleName); 47 | Requires.NotNullOrEmpty("DnnRoleName", dnnRoleName); 48 | Requires.NotNullOrEmpty("AadRoleName", aadRoleName); 49 | 50 | var roleMapping = GetRoleMapping(originalDnnRoleName, portalId); 51 | if (roleMapping == null) 52 | { 53 | throw new ArgumentException($"Role mapping '{originalDnnRoleName}' not found in portal {portalId}"); 54 | } 55 | 56 | roleMapping.DnnRoleName = dnnRoleName; 57 | roleMapping.AadRoleName = aadRoleName; 58 | roleMapping.PortalId = portalId; 59 | roleMapping.LastModifiedOnDate = DateTime.UtcNow; 60 | roleMapping.LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID; 61 | using (IDataContext ctx = DataContext.Instance()) 62 | { 63 | var rep = ctx.GetRepository(); 64 | rep.Update(roleMapping); 65 | } 66 | } 67 | 68 | public void InsertRoleMapping(string dnnRoleName, string aadRoleName, int portalId) 69 | { 70 | Requires.NotNullOrEmpty("DnnRoleName", dnnRoleName); 71 | Requires.NotNullOrEmpty("AadRoleName", aadRoleName); 72 | 73 | var roleMapping = new RoleMapping 74 | { 75 | DnnRoleName = dnnRoleName, 76 | CreatedByUserId = UserController.Instance.GetCurrentUserInfo().UserID, 77 | CreatedOnDate = DateTime.UtcNow, 78 | AadRoleName = aadRoleName, 79 | PortalId = portalId, 80 | LastModifiedOnDate = DateTime.UtcNow, 81 | LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID 82 | }; 83 | using (IDataContext ctx = DataContext.Instance()) 84 | { 85 | var rep = ctx.GetRepository(); 86 | rep.Insert(roleMapping); 87 | } 88 | } 89 | 90 | public void DeleteRoleMapping(string dnnRoleName, int portalId) 91 | { 92 | Requires.NotNullOrEmpty("DnnRoleName", dnnRoleName); 93 | 94 | var roleMapping = GetRoleMapping(dnnRoleName, portalId); 95 | if (roleMapping != null) 96 | { 97 | using (IDataContext ctx = DataContext.Instance()) 98 | { 99 | var rep = ctx.GetRepository(); 100 | rep.Delete(roleMapping); 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Data/ProfileMappingsRepository.cs: -------------------------------------------------------------------------------- 1 | using DotNetNuke.Authentication.Azure.Components.Models; 2 | using DotNetNuke.Common; 3 | using DotNetNuke.Data; 4 | using DotNetNuke.Entities.Users; 5 | using DotNetNuke.Framework; 6 | using System; 7 | using System.Linq; 8 | 9 | namespace DotNetNuke.Authentication.Azure.Data 10 | { 11 | public class ProfileMappingsRepository : ServiceLocator, IProfileMappingsRepository 12 | { 13 | protected override Func GetFactory() 14 | { 15 | return () => new ProfileMappingsRepository(); 16 | } 17 | 18 | public IQueryable GetProfileMappings(int portalId) 19 | { 20 | IQueryable result = null; 21 | 22 | using (IDataContext ctx = DataContext.Instance()) 23 | { 24 | var rep = ctx.GetRepository(); 25 | result = rep.Find("WHERE PortalId = @0", portalId).AsQueryable(); 26 | } 27 | 28 | return result; 29 | } 30 | 31 | public ProfileMapping GetProfileMapping(string dnnProfilePropertyName, int portalId) 32 | { 33 | Requires.NotNullOrEmpty("DnnProfilePropertyName", dnnProfilePropertyName); 34 | 35 | ProfileMapping result; 36 | using (IDataContext ctx = DataContext.Instance()) 37 | { 38 | var rep = ctx.GetRepository(); 39 | result = rep.Find("WHERE DnnProfilePropertyName = @0 AND PortalId = @1", dnnProfilePropertyName, portalId).FirstOrDefault(); 40 | } 41 | return result; 42 | } 43 | 44 | public void UpdateProfileMapping(string dnnProfilePropertyName, string aadClaimName, int portalId) 45 | { 46 | Requires.NotNullOrEmpty("DnnProfilePropertyName", dnnProfilePropertyName); 47 | Requires.NotNullOrEmpty("AadClaimName", aadClaimName); 48 | 49 | var profileMapping = GetProfileMapping(dnnProfilePropertyName, portalId); 50 | if (profileMapping == null) 51 | { 52 | throw new ArgumentException($"Profile mapping '{dnnProfilePropertyName}' not found in portal {portalId}"); 53 | } 54 | 55 | profileMapping.AadClaimName = aadClaimName; 56 | profileMapping.PortalId = portalId; 57 | profileMapping.LastModifiedOnDate = DateTime.UtcNow; 58 | profileMapping.LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID; 59 | using (IDataContext ctx = DataContext.Instance()) 60 | { 61 | var rep = ctx.GetRepository(); 62 | rep.Update(profileMapping); 63 | } 64 | } 65 | 66 | public void InsertProfileMapping(string dnnProfilePropertyName, string aadClaimName, int portalId) 67 | { 68 | Requires.NotNullOrEmpty("DnnProfilePropertyName", dnnProfilePropertyName); 69 | Requires.NotNullOrEmpty("AadClaimName", aadClaimName); 70 | 71 | var profileMapping = new ProfileMapping 72 | { 73 | DnnProfilePropertyName = dnnProfilePropertyName, 74 | CreatedByUserId = UserController.Instance.GetCurrentUserInfo().UserID, 75 | CreatedOnDate = DateTime.UtcNow, 76 | AadClaimName = aadClaimName, 77 | PortalId = portalId, 78 | LastModifiedOnDate = DateTime.UtcNow, 79 | LastModifiedByUserId = UserController.Instance.GetCurrentUserInfo().UserID 80 | }; 81 | using (IDataContext ctx = DataContext.Instance()) 82 | { 83 | var rep = ctx.GetRepository(); 84 | rep.Insert(profileMapping); 85 | } 86 | } 87 | 88 | public void DeleteProfileMapping(string dnnProfilePropertyName, int portalId) 89 | { 90 | Requires.NotNullOrEmpty("DnnProfilePropertyname", dnnProfilePropertyName); 91 | 92 | var profileMapping = GetProfileMapping(dnnProfilePropertyName, portalId); 93 | if (profileMapping != null) 94 | { 95 | using (IDataContext ctx = DataContext.Instance()) 96 | { 97 | var rep = ctx.GetRepository(); 98 | rep.Delete(profileMapping); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Login.ascx.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2010-2017 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | #region Usings 25 | 26 | using System; 27 | using System.Collections.Specialized; 28 | using System.Diagnostics; 29 | using System.Web; 30 | using DotNetNuke.Authentication.Azure.Components; 31 | using DotNetNuke.Services.Authentication; 32 | using DotNetNuke.Services.Authentication.OAuth; 33 | using DotNetNuke.Services.Exceptions; 34 | using DotNetNuke.Services.Localization; 35 | using DotNetNuke.UI.Skins.Controls; 36 | using log4net; 37 | 38 | #endregion 39 | 40 | namespace DotNetNuke.Authentication.Azure 41 | { 42 | public partial class Login : OAuthLoginBase 43 | { 44 | private ILog _logger = LogManager.GetLogger(typeof(Login)); 45 | private AzureConfig config; 46 | protected override string AuthSystemApplicationName => AzureConfig.ServiceName; 47 | 48 | public override bool SupportsRegistration => true; 49 | 50 | protected override void AddCustomProperties(NameValueCollection properties) 51 | { 52 | ((AzureClient)OAuthClient).AddCustomProperties(properties); 53 | } 54 | 55 | protected override UserData GetCurrentUser() 56 | { 57 | return OAuthClient.GetCurrentUser(); 58 | } 59 | 60 | protected override void OnInit(EventArgs e) 61 | { 62 | base.OnInit(e); 63 | 64 | 65 | loginButton.Click += loginButton_Click; 66 | registerButton.Click += loginButton_Click; 67 | 68 | OAuthClient = new AzureClient(PortalId, Mode); 69 | 70 | loginItem.Visible = (Mode == AuthMode.Login); 71 | registerItem.Visible = (Mode == AuthMode.Register); 72 | 73 | config = new AzureConfig(AzureConfig.ServiceName, PortalId); 74 | var hasVerificationCode = ((AzureClient)OAuthClient).IsCurrentService() && OAuthClient.HaveVerificationCode(); 75 | if ((config.AutoRedirect && Request["legacy"] != "1") || hasVerificationCode || !string.IsNullOrEmpty(Request["error"])) 76 | loginButton_Click(null, null); 77 | } 78 | 79 | private void loginButton_Click(object sender, EventArgs e) 80 | { 81 | if (!string.IsNullOrEmpty(Request["error"])) 82 | { 83 | var errorMessage = Localization.GetString("LoginError", LocalResourceFile); 84 | errorMessage = string.Format(errorMessage, Request["error"], Request["error_description"]); 85 | _logger.Error(errorMessage); 86 | if (string.IsNullOrEmpty(config.OnErrorUri)) 87 | { 88 | UI.Skins.Skin.AddModuleMessage(this, errorMessage, ModuleMessage.ModuleMessageType.RedError); 89 | } 90 | else 91 | { 92 | Response.Redirect($"{config.OnErrorUri}?error={Request["error"]}&error_description={HttpContext.Current.Server.UrlEncode(Request["error_description"])}"); 93 | } 94 | } 95 | else 96 | { 97 | AuthorisationResult result = OAuthClient.Authorize(); 98 | if (result == AuthorisationResult.Denied) 99 | { 100 | if (string.IsNullOrEmpty(config.OnErrorUri)) 101 | { 102 | UI.Skins.Skin.AddModuleMessage(this, Localization.GetString("PrivateConfirmationMessage", Localization.SharedResourceFile), ModuleMessage.ModuleMessageType.YellowWarning); 103 | } 104 | else 105 | { 106 | Response.Redirect($"{config.OnErrorUri}?error=Denied&error_description={HttpContext.Current.Server.UrlEncode(Localization.GetString("PrivateConfirmationMessage", Localization.SharedResourceFile))}"); 107 | } 108 | } 109 | else 110 | { 111 | if (!string.IsNullOrEmpty(((AzureClient)OAuthClient).RedirectUrl)) { 112 | RedirectURL = ((AzureClient)OAuthClient).RedirectUrl; 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Providers/DataProviders/SqlDataProvider/04.00.00.SqlDataProvider: -------------------------------------------------------------------------------- 1 | IF NOT EXISTS (SELECT * FROM {databaseOwner}[{objectQualifier}Schedule] WHERE TypeFullName = 'DotNetNuke.Authentication.Azure.ScheduledTasks.SyncSchedule, DotNetNuke.Authentication.Azure') 2 | BEGIN 3 | INSERT INTO {databaseOwner}[{objectQualifier}Schedule] 4 | ([TypeFullName] 5 | ,[TimeLapse] 6 | ,[TimeLapseMeasurement] 7 | ,[RetryTimeLapse] 8 | ,[RetryTimeLapseMeasurement] 9 | ,[RetainHistoryNum] 10 | ,[AttachToEvent] 11 | ,[CatchUpEnabled] 12 | ,[Enabled] 13 | ,[ObjectDependencies] 14 | ,[Servers] 15 | ,[CreatedByUserID] 16 | ,[CreatedOnDate] 17 | ,[LastModifiedByUserID] 18 | ,[LastModifiedOnDate] 19 | ,[FriendlyName]) 20 | VALUES 21 | ('DotNetNuke.Authentication.Azure.ScheduledTasks.SyncSchedule, DotNetNuke.Authentication.Azure', 22 | 3, 'h', 23 | 30, 'm', 24 | 10, 25 | '', 'false', 'true', 26 | '', NULL, 27 | NULL, NULL, 28 | NULL, NULL, 29 | 'Azure AD Sync') 30 | END 31 | 32 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_UserMappings]', N'U') IS NULL 33 | BEGIN 34 | CREATE TABLE {databaseOwner}[{objectQualifier}AzureAD_UserMappings]( 35 | [UserMappingId] [int] NOT NULL IDENTITY (1, 1), 36 | [DnnPropertyName] [nvarchar](50) NOT NULL, 37 | [AadClaimName] [nvarchar](100) NULL, 38 | [PortalId] [int] NULL, 39 | [CreatedByUserId] [int] NULL, 40 | [CreatedOnDate] [datetime] NULL, 41 | [LastModifiedByUserId] [int] NULL, 42 | [LastModifiedOnDate] [datetime] NULL, 43 | CONSTRAINT [PK_AzureAD_UserMappings] PRIMARY KEY CLUSTERED 44 | ( 45 | [UserMappingId] ASC 46 | ) ON [PRIMARY] 47 | ) ON [PRIMARY] 48 | 49 | -- Insert default values: 50 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 51 | SELECT 'PortalId', '', PortalId, -1, GETDATE(), -1, GETDATE() 52 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 53 | 54 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 55 | SELECT 'Id', 'upn', PortalID, -1, GETDATE(), -1, GETDATE() 56 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 57 | 58 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 59 | SELECT 'FirstName', 'given_name', PortalId, -1, GETDATE(), -1, GETDATE() 60 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 61 | 62 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 63 | SELECT 'LastName', 'family_name', PortalId, -1, GETDATE(), -1, GETDATE() 64 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 65 | 66 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 67 | SELECT 'DisplayName', 'name', PortalId, -1, GETDATE(), -1, GETDATE() 68 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 69 | 70 | INSERT INTO {databaseOwner}[{objectQualifier}AzureAD_UserMappings] ([DnnPropertyName],[AadClaimName],[PortalId],[CreatedByUserId],[CreatedOnDate],[LastModifiedByUserId],[LastModifiedOnDate]) 71 | SELECT 'Email', 'upn', PortalId, -1, GETDATE(), -1, GETDATE() 72 | FROM (Select PortalId FROM {databaseOwner}[{objectQualifier}Portals] UNION SELECT PortalId = -1) p 73 | END 74 | GO 75 | 76 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_ProfileMappings]', N'U') IS NULL 77 | BEGIN 78 | CREATE TABLE {databaseOwner}[{objectQualifier}AzureAD_ProfileMappings]( 79 | [ProfileMappingId] [int] NOT NULL IDENTITY (1, 1), 80 | [DnnProfilePropertyName] [nvarchar](50) NOT NULL, 81 | [AadClaimName] [nvarchar](100) NULL, 82 | [PortalId] [int] NULL, 83 | [CreatedByUserId] [int] NULL, 84 | [CreatedOnDate] [datetime] NULL, 85 | [LastModifiedByUserId] [int] NULL, 86 | [LastModifiedOnDate] [datetime] NULL, 87 | CONSTRAINT [PK_AzureAD_ProfileMappings] PRIMARY KEY CLUSTERED 88 | ( 89 | [ProfileMappingId] ASC 90 | ) ON [PRIMARY] 91 | ) ON [PRIMARY] 92 | 93 | END 94 | GO 95 | 96 | IF OBJECT_ID(N'{databaseOwner}[{objectQualifier}AzureAD_RoleMappings]', N'U') IS NULL 97 | BEGIN 98 | CREATE TABLE {databaseOwner}[{objectQualifier}AzureAD_RoleMappings]( 99 | [RoleMappingId] [int] NOT NULL IDENTITY (1, 1), 100 | [DnnRoleName] [nvarchar](50) NOT NULL, 101 | [AadRoleName] [nvarchar](100) NULL, 102 | [PortalId] [int] NULL, 103 | [CreatedByUserId] [int] NULL, 104 | [CreatedOnDate] [datetime] NULL, 105 | [LastModifiedByUserId] [int] NULL, 106 | [LastModifiedOnDate] [datetime] NULL, 107 | CONSTRAINT [PK_AzureAD_RoleMappings] PRIMARY KEY CLUSTERED 108 | ( 109 | [RoleMappingId] ASC 110 | ) ON [PRIMARY] 111 | ) ON [PRIMARY] 112 | 113 | END 114 | GO 115 | 116 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/reducers/settingsReducer.js: -------------------------------------------------------------------------------- 1 | import { settings as ActionTypes } from "../constants/actionTypes"; 2 | 3 | export default function settings(state = { 4 | selectedTab: 0 5 | }, action) { 6 | switch (action.type) { 7 | case ActionTypes.RETRIEVED_SETTINGS: 8 | return { ...state, 9 | enabled: action.data.enabled, 10 | useGlobalSettings: action.data.useGlobalSettings, 11 | autoRedirect: action.data.autoRedirect, 12 | autoAuthorize: action.data.autoAuthorize, 13 | autoMatchExistingUsers: action.data.autoMatchExistingUsers, 14 | apiKey: action.data.apiKey, 15 | apiSecret: action.data.apiSecret, 16 | redirectUri: action.data.redirectUri, 17 | onErrorUri: action.data.onErrorUri, 18 | tenantId: action.data.tenantId, 19 | aadTenantId: action.data.aadTenantId, 20 | aadAppClientId: action.data.aadAppClientId, 21 | aadAppSecret: action.data.aadAppSecret, 22 | graphUseCustomParams: action.data.graphUseCustomParams, 23 | jwtAudiences: action.data.jwtAudiences, 24 | roleSyncEnabled: action.data.roleSyncEnabled, 25 | userSyncEnabled: action.data.userSyncEnabled, 26 | profileSyncEnabled: action.data.profileSyncEnabled, 27 | apiResource: action.data.apiResource, 28 | scopes: action.data.scopes, 29 | clientModified: action.data.clientModified, 30 | usernamePrefixEnabled: action.data.usernamePrefixEnabled, 31 | groupNamePrefixEnabled: action.data.groupNamePrefixEnabled, 32 | authorizationCodePrompt: action.data.authorizationCodePrompt, 33 | domainHint: action.data.domainHint 34 | }; 35 | case ActionTypes.SETTINGS_CLIENT_MODIFIED: 36 | return { ...state, 37 | enabled: action.data.enabled, 38 | useGlobalSettings: action.data.useGlobalSettings, 39 | autoRedirect: action.data.autoRedirect, 40 | autoAuthorize: action.data.autoAuthorize, 41 | autoMatchExistingUsers: action.data.autoMatchExistingUsers, 42 | apiKey: action.data.apiKey, 43 | apiSecret: action.data.apiSecret, 44 | redirectUri: action.data.redirectUri, 45 | onErrorUri: action.data.onErrorUri, 46 | tenantId: action.data.tenantId, 47 | aadTenantId: action.data.aadTenantId, 48 | aadAppClientId: action.data.aadAppClientId, 49 | aadAppSecret: action.data.aadAppSecret, 50 | graphUseCustomParams: action.data.graphUseCustomParams, 51 | jwtAudiences: action.data.jwtAudiences, 52 | roleSyncEnabled: action.data.roleSyncEnabled, 53 | userSyncEnabled: action.data.userSyncEnabled, 54 | profileSyncEnabled: action.data.profileSyncEnabled, 55 | apiResource: action.data.apiResource, 56 | scopes: action.data.scopes, 57 | clientModified: action.data.clientModified, 58 | usernamePrefixEnabled: action.data.usernamePrefixEnabled, 59 | groupNamePrefixEnabled: action.data.groupNamePrefixEnabled, 60 | authorizationCodePrompt: action.data.authorizationCodePrompt, 61 | domainHint: action.data.domainHint 62 | }; 63 | case ActionTypes.UPDATED_SETTINGS: 64 | return { ...state, 65 | clientModified: action.data.clientModified 66 | }; 67 | case ActionTypes.RETRIEVED_PROFILESETTINGS: 68 | return { ...state, 69 | profileMapping: action.data.profileMapping 70 | }; 71 | case ActionTypes.RETRIEVED_ROLEMAPPINGSETTINGS: 72 | return { ...state, 73 | roleMapping: action.data.roleMapping 74 | }; 75 | case ActionTypes.RETRIEVED_AVAILABLEROLES: 76 | return { ...state, 77 | roles: action.data.roles 78 | }; 79 | case ActionTypes.SWITCH_TAB: 80 | return { 81 | ...state, 82 | selectedTab: action.payload 83 | }; 84 | case ActionTypes.SWITCH_MAPPING_SUBTAB: 85 | return { 86 | ...state, 87 | selectedSubTab: action.payload 88 | }; 89 | case ActionTypes.CANCELLED_PROFILEMAPPING_CLIENT_MODIFIED: 90 | return { ...state, 91 | profileMappingClientModified: action.data.profileMappingClientModified 92 | }; 93 | case ActionTypes.PROFILEMAPPINGS_CLIENT_MODIFIED: 94 | return { ...state, 95 | profileMappingDetail: action.data.profileMappingDetail, 96 | profileMappingClientModified: action.data.profileMappingClientModified 97 | }; 98 | case ActionTypes.RETRIEVED_PROFILEPROPERTIES: 99 | return { ...state, 100 | profileProperties: action.data.profileProperties 101 | }; 102 | case ActionTypes.ROLEMAPPINGS_CLIENT_MODIFIED: 103 | return { ...state, 104 | roleProperties: action.data.roleProperties 105 | }; 106 | case ActionTypes.RETRIEVED_USERMAPPINGSETTINGS: 107 | return { ...state, 108 | userMapping: action.data.userMapping 109 | }; 110 | case ActionTypes.USERMAPPINGS_CLIENT_MODIFIED: 111 | return { ...state, 112 | userMappingDetail: action.data.userMappingDetail, 113 | userMappingClientModified: action.data.userMappingClientModified 114 | }; 115 | default: 116 | return { ...state 117 | }; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/App_LocalResources/Settings.ascx.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Microosft Entra ID Settings 122 | 123 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/App_LocalResources/Login.ascx.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | Sign in with Microsoft Entra ID 122 | 123 | 124 | Error: {0}<br/>Details: {1} 125 | 126 | 127 | Register with Microsoft Entra ID 128 | 129 | 130 | Microsoft Entra ID 131 | 132 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/index.jsx: -------------------------------------------------------------------------------- 1 | import React, {Component} from "react"; 2 | import PropTypes from "prop-types"; 3 | import { connect } from "react-redux"; 4 | import SettingsActions from "../../actions/settings"; 5 | import UserMappingRow from "./userMappingRow"; 6 | import UserMappingEditor from "./userMappingEditor"; 7 | import "./style.less"; 8 | import utils from "../../utils"; 9 | import resx from "../../resources"; 10 | 11 | class UserMappings extends Component { 12 | 13 | constructor() { 14 | super(); 15 | 16 | this.state = { 17 | openId: "", 18 | tableFields: [], 19 | error: { 20 | mapping: false 21 | } 22 | }; 23 | } 24 | UNSAFE_componentWillMount() { 25 | const {props} = this; 26 | 27 | props.dispatch(SettingsActions.getUserMappingSettings()); 28 | } 29 | 30 | UNSAFE_componentWillReceiveProps(nextProps) { 31 | const {state} = this; 32 | 33 | state.error["mapping"] = (nextProps.mapping === null); 34 | } 35 | 36 | onUpdateMapping(mappingDetail) { 37 | const {props} = this; 38 | 39 | let payload = { 40 | DnnPropertyName: mappingDetail.DnnPropertyName, 41 | AadClaimName: mappingDetail.AadClaimName 42 | }; 43 | props.dispatch(SettingsActions.updateUserMapping(payload, () => { 44 | utils.utilities.notify(resx.get("MappingUpdateSuccess")); 45 | this.collapse(); 46 | props.dispatch(SettingsActions.getUserMappingSettings()); 47 | }, (error) => { 48 | const errorMessage = JSON.parse(error.responseText); 49 | utils.utilities.notifyError(errorMessage.Message); 50 | })); 51 | } 52 | 53 | onDeleteMapping(mappingId) { 54 | const {props} = this; 55 | utils.utilities.confirm(resx.get("MappingDeletedWarning"), resx.get("Yes"), resx.get("No"), () => { 56 | let originalUserMappingName = mappingId.split("-")[0]; 57 | 58 | let payload = { 59 | dnnMappingName: originalUserMappingName 60 | }; 61 | props.dispatch(SettingsActions.deleteUserMapping(payload, () => { 62 | utils.utilities.notify(resx.get("MappingDeleteSuccess")); 63 | this.collapse(); 64 | props.dispatch(SettingsActions.getUserMappingSettings()); 65 | }, (error) => { 66 | const errorMessage = JSON.parse(error.responseText); 67 | utils.utilities.notifyError(errorMessage.Message); 68 | })); 69 | }); 70 | } 71 | 72 | onClickCancel() { 73 | utils.utilities.closePersonaBar(); 74 | } 75 | 76 | /* eslint-disable react/no-did-update-set-state */ 77 | componentDidUpdate(prevProps) { 78 | const {props} = this; 79 | if (props !== prevProps) { 80 | let tableFields = []; 81 | if (tableFields.length === 0) { 82 | tableFields.push({ "name": resx.get("DnnProperty.Header"), "id": "DnnProperty" }); 83 | tableFields.push({ "name": resx.get("AadProperty.Header"), "id": "AadProperty" }); 84 | } 85 | this.setState({tableFields}); 86 | } 87 | } 88 | 89 | uncollapse(id) { 90 | this.setState({ 91 | openId: id 92 | }); 93 | } 94 | 95 | collapse() { 96 | if (this.state.openId !== "") { 97 | this.setState({ 98 | openId: "" 99 | }); 100 | } 101 | } 102 | 103 | toggle(openId) { 104 | if (openId !== "") { 105 | this.uncollapse(openId); 106 | } 107 | } 108 | 109 | renderHeader() { 110 | let tableHeaders = this.state.tableFields.map((field) => { 111 | let className = "header-" + field.id; 112 | return
    113 | {field.name}  114 |
    ; 115 | }); 116 | return
    {tableHeaders}
    ; 117 | } 118 | 119 | renderMappings() { 120 | let i = 0; 121 | if (this.props.mapping) { 122 | return this.props.mapping.map((item, index) => { 123 | let id = "row-" + i++; 124 | let mappingId = item.DnnPropertyName + "-" + item.AadClaimName; 125 | return ( 126 | 138 | 146 | 147 | ); 148 | }); 149 | } 150 | } 151 | 152 | /* eslint-disable react/no-danger */ 153 | render() { 154 | return ( 155 |
    156 |
    157 |
    158 |
    {resx.get("lblUsersMapping")}
    159 |
    160 |
    161 | {this.renderHeader()} 162 | {this.renderMappings()} 163 |
    164 |
    165 |
    166 | ); 167 | } 168 | } 169 | 170 | UserMappings.propTypes = { 171 | mapping: PropTypes.array 172 | }; 173 | 174 | 175 | function mapStateToProps(state) { 176 | return { 177 | mapping: state.settings.userMapping 178 | }; 179 | } 180 | 181 | export default connect(mapStateToProps)(UserMappings); -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Components/Graph/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graph; 2 | using Microsoft.Identity.Client; 3 | using System.IO; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace DotNetNuke.Authentication.Azure.Components.Graph 8 | { 9 | // Added Sync extensions methods because the current Graph nuget package is 10 | // getting frozen on async calls. Horrible workaround but can't get it working. 11 | // See https://stackoverflow.com/questions/55105321/microsoft-graph-getasync-hangs-indefinitely 12 | // See https://stackoverflow.com/questions/66109869/getting-an-access-token-for-the-graph-api-works-in-a-console-app-but-just-hangs 13 | internal static class GraphExtensions 14 | { 15 | internal static IUserMemberOfCollectionWithReferencesPage GetSync(this IUserMemberOfCollectionWithReferencesRequest request) 16 | { 17 | using (var task = Task.Run(async () => await request.GetAsync())) 18 | { 19 | while (!task.IsCompleted) 20 | Thread.Sleep(10); 21 | return task.Result; 22 | } 23 | } 24 | internal static User GetSync(this IUserRequest request) 25 | { 26 | using (var task = Task.Run(async () => await request.GetAsync())) 27 | { 28 | while (!task.IsCompleted) 29 | Thread.Sleep(10); 30 | return task.Result; 31 | } 32 | } 33 | 34 | internal static ProfilePhoto GetSync(this IProfilePhotoRequest request) 35 | { 36 | using (var task = Task.Run(async () => await request.GetAsync())) 37 | { 38 | while (!task.IsCompleted) 39 | Thread.Sleep(10); 40 | return task.Result; 41 | } 42 | } 43 | 44 | internal static Stream GetSync(this IProfilePhotoContentRequest request) 45 | { 46 | using (var task = Task.Run(async () => await request.GetAsync())) 47 | { 48 | while (!task.IsCompleted) 49 | Thread.Sleep(10); 50 | return task.Result; 51 | } 52 | } 53 | 54 | 55 | 56 | internal static void DeleteSync(this IUserRequest request) 57 | { 58 | using (var task = Task.Run(async () => await request.DeleteAsync())) 59 | { 60 | while (!task.IsCompleted) 61 | Thread.Sleep(10); 62 | return; 63 | } 64 | } 65 | 66 | internal static IGraphServiceUsersCollectionPage GetSync(this IGraphServiceUsersCollectionRequest request) 67 | { 68 | using (var task = Task.Run(async () => await request.GetAsync())) 69 | { 70 | while (!task.IsCompleted) 71 | Thread.Sleep(10); 72 | return task.Result; 73 | } 74 | } 75 | 76 | internal static User AddSync(this IGraphServiceUsersCollectionRequest request, User user) 77 | { 78 | using (var task = Task.Run(async () => await request.AddAsync(user))) 79 | { 80 | while (!task.IsCompleted) 81 | Thread.Sleep(10); 82 | return task.Result; 83 | } 84 | } 85 | 86 | internal static User UpdateSync(this IUserRequest request, User user) 87 | { 88 | using (var task = Task.Run(async () => await request.UpdateAsync(user))) 89 | { 90 | while (!task.IsCompleted) 91 | Thread.Sleep(10); 92 | return task.Result; 93 | } 94 | } 95 | 96 | internal static IGraphServiceGroupsCollectionPage GetSync(this IGraphServiceGroupsCollectionRequest request) 97 | { 98 | using (var task = Task.Run(async () => await request.GetAsync())) 99 | { 100 | while (!task.IsCompleted) 101 | Thread.Sleep(10); 102 | return task.Result; 103 | } 104 | } 105 | 106 | internal static IGroupTransitiveMembersCollectionWithReferencesPage GetSync(this IGroupTransitiveMembersCollectionWithReferencesRequest request) 107 | { 108 | using (var task = Task.Run(async () => await request.GetAsync())) 109 | { 110 | while (!task.IsCompleted) 111 | Thread.Sleep(10); 112 | return task.Result; 113 | } 114 | } 115 | 116 | 117 | internal static Group AddSync(this IGraphServiceGroupsCollectionRequest request, Group group) 118 | { 119 | using (var task = Task.Run(async () => await request.AddAsync(group))) 120 | { 121 | while (!task.IsCompleted) 122 | Thread.Sleep(10); 123 | return task.Result; 124 | } 125 | } 126 | 127 | 128 | 129 | internal static Group UpdateSync(this IGroupRequest request, Group group) 130 | { 131 | using (var task = Task.Run(async () => await request.UpdateAsync(group))) 132 | { 133 | while (!task.IsCompleted) 134 | Thread.Sleep(10); 135 | return task.Result; 136 | } 137 | } 138 | 139 | 140 | internal static void AddSync(this IGroupMembersCollectionReferencesRequest request, User user) 141 | { 142 | using (var task = Task.Run(async () => await request.AddAsync(user))) 143 | { 144 | while (!task.IsCompleted) 145 | Thread.Sleep(10); 146 | return; 147 | } 148 | } 149 | 150 | internal static void DeleteSync(this IDirectoryObjectReferenceRequest request) 151 | { 152 | using (var task = Task.Run(async () => await request.DeleteAsync())) 153 | { 154 | while (!task.IsCompleted) 155 | Thread.Sleep(10); 156 | return; 157 | } 158 | } 159 | 160 | 161 | internal static AuthenticationResult ExecuteSync(this AcquireTokenForClientParameterBuilder request) 162 | { 163 | using (var task = Task.Run(async () => await request.ExecuteAsync())) 164 | { 165 | while (!task.IsCompleted) 166 | Thread.Sleep(10); 167 | return task.Result; 168 | } 169 | } 170 | 171 | internal static T RunSynchronous(this Task t) 172 | { 173 | using (var task = Task.Run(async () => await t)) 174 | { 175 | while (!task.IsCompleted) 176 | Thread.Sleep(10); 177 | return task.Result; 178 | } 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/userMappings/userMappingEditor/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { connect } from "react-redux"; 4 | import "./style.less"; 5 | import { SingleLineInputWithError, GridSystem, Button, InputGroup } from "@dnnsoftware/dnn-react-common"; 6 | import SettingsActions from "../../../actions/settings"; 7 | import util from "../../../utils"; 8 | import resx from "../../../resources"; 9 | 10 | class UserMappingEditor extends Component { 11 | constructor() { 12 | super(); 13 | 14 | this.state = { 15 | mappingDetail: { 16 | DnnPropertyName: "", 17 | AadClaimName: "" 18 | }, 19 | error: { 20 | dnnPropertyName: false, 21 | aadClaimName: false 22 | }, 23 | triedToSubmit: false 24 | }; 25 | } 26 | 27 | componentWillMount() { 28 | const {props} = this; 29 | const {state} = this; 30 | 31 | state.mappingDetail["MappingId"] = props.mappingId; 32 | state.mappingDetail["DnnPropertyName"] = props.dnnPropertyName; 33 | state.mappingDetail["AadClaimName"] = props.aadClaimName; 34 | 35 | state.error["dnnPropertyName"] = (props.dnnPropertyName === null); 36 | state.error["aadClaimName"] = (props.aadClaimName === null); 37 | } 38 | 39 | /* eslint-disable react/no-did-update-set-state */ 40 | componentDidUpdate(prevProps) { 41 | const {props, state} = this; 42 | if ((props !== prevProps) && props.mappingDetail ) { 43 | if (props.mappingDetail["DnnPropertyName"] === undefined || props.mappingDetail["DnnPropertyName"] === "") { 44 | state.error["dnnPropertyName"] = true; 45 | } 46 | else if (props.mappingDetail["DnnPropertyName"] !== "" && props.mappingDetail["DnnPropertyName"] !== undefined) { 47 | state.error["dnnPropertyName"] = false; 48 | } 49 | 50 | this.setState({ 51 | mappingDetail: Object.assign({}, props.mappingDetail), 52 | triedToSubmit: false, 53 | error: state.error 54 | }); 55 | } 56 | } 57 | 58 | onSettingChange(key, event) { 59 | let {state, props} = this; 60 | let mappingDetail = Object.assign({}, state.mappingDetail); 61 | 62 | if (key === "DnnPropertyName") { 63 | state.error["dnnPropertyName"] = !props.onValidate(mappingDetail, event.value); 64 | } 65 | 66 | if (mappingDetail[key] === "" && key === "AadClaimName" && props.dnnPropertyName !== "PortalId") { 67 | state.error["aadClaimName"] = true; 68 | } 69 | else if (mappingDetail[key] !== "" && key === "AadClaimName") { 70 | state.error["aadClaimName"] = false; 71 | } 72 | 73 | mappingDetail[key] = typeof (event) === "object" ? event.target.value : event; 74 | 75 | this.setState({ 76 | mappingDetail: mappingDetail, 77 | triedToSubmit: false, 78 | error: state.error 79 | }); 80 | 81 | props.dispatch(SettingsActions.userMappingClientModified(mappingDetail)); 82 | } 83 | 84 | onSave() { 85 | const {props, state} = this; 86 | this.setState({ 87 | triedToSubmit: true 88 | }); 89 | if (state.error.dnnPropertyName || state.error.aadClaimName) { 90 | return; 91 | } 92 | 93 | props.onUpdate(state.mappingDetail); 94 | props.Collapse(); 95 | } 96 | 97 | onCancel() { 98 | const {props} = this; 99 | 100 | if (props.mappingClientModified) { 101 | util.utilities.confirm(resx.get("SettingsRestoreWarning"), resx.get("Yes"), resx.get("No"), () => { 102 | props.dispatch(SettingsActions.cancelUserMappingClientModified()); 103 | props.Collapse(); 104 | }); 105 | } 106 | else { 107 | props.Collapse(); 108 | } 109 | } 110 | 111 | /* eslint-disable react/no-danger */ 112 | render() { 113 | if (this.state.mappingDetail !== undefined || this.props.id === "add") { 114 | const columnOne =
    115 | 116 | 124 | 125 |
    ; 126 | const columnTwo =
    127 | 128 | 138 | 139 |
    ; 140 | 141 | return ( 142 |
    143 | {[columnOne, columnTwo]} 144 |
    145 | 150 | 155 |
    156 |
    157 | ); 158 | } 159 | else return
    ; 160 | } 161 | } 162 | 163 | UserMappingEditor.propTypes = { 164 | dispatch: PropTypes.func.isRequired, 165 | mappingDetail: PropTypes.object, 166 | mappingId: PropTypes.string, 167 | dnnPropertyName: PropTypes.string, 168 | aadClaimName: PropTypes.string, 169 | Collapse: PropTypes.func, 170 | onUpdate: PropTypes.func, 171 | id: PropTypes.string, 172 | mappingClientModified: PropTypes.bool, 173 | onValidate: PropTypes.func 174 | }; 175 | 176 | function mapStateToProps() { 177 | return { 178 | }; 179 | } 180 | 181 | export default connect(mapStateToProps)(UserMappingEditor); -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/AzureAD.Web/src/components/roleMappings/roleMappingEditor/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { connect } from "react-redux"; 4 | import "./style.less"; 5 | import { SingleLineInputWithError, GridSystem, Button, InputGroup, DropdownWithError } from "@dnnsoftware/dnn-react-common"; 6 | import SettingsActions from "../../../actions/settings"; 7 | import util from "../../../utils"; 8 | import resx from "../../../resources"; 9 | 10 | class RoleMappingEditor extends Component { 11 | constructor() { 12 | super(); 13 | 14 | this.state = { 15 | mappingDetail: { 16 | DnnRoleName: "", 17 | AadRoleName: "" 18 | }, 19 | error: { 20 | dnnRoleName: false, 21 | aadRoleName: false 22 | }, 23 | triedToSubmit: false 24 | }; 25 | } 26 | 27 | componentWillMount() { 28 | const {props} = this; 29 | const {state} = this; 30 | 31 | state.mappingDetail["MappingId"] = props.mappingId; 32 | state.mappingDetail["DnnRoleName"] = props.dnnRoleName; 33 | state.mappingDetail["AadRoleName"] = props.aadRoleName; 34 | 35 | state.error["dnnRoleName"] = (props.dnnRoleName === null); 36 | state.error["aadRoleName"] = (props.aadRoleName === null); 37 | } 38 | 39 | /* eslint-disable react/no-did-update-set-state */ 40 | componentDidUpdate(prevProps) { 41 | const {props, state} = this; 42 | if ((props !== prevProps) && props.mappingDetail ) { 43 | if (props.mappingDetail["DnnRoleName"] === undefined || props.mappingDetail["DnnRoleName"] === "") { 44 | state.error["dnnRoleName"] = true; 45 | } 46 | else if (props.mappingDetail["DnnRoleName"] !== "" && props.mappingDetail["DnnRoleName"] !== undefined) { 47 | state.error["dnnRoleName"] = false; 48 | } 49 | 50 | this.setState({ 51 | mappingDetail: Object.assign({}, props.mappingDetail), 52 | triedToSubmit: false, 53 | error: state.error 54 | }); 55 | } 56 | } 57 | 58 | onSettingChange(key, event) { 59 | let {state, props} = this; 60 | let mappingDetail = Object.assign({}, state.mappingDetail); 61 | 62 | if (key === "DnnRoleName") { 63 | state.error["dnnRoleName"] = !props.onValidate(mappingDetail, event.value); 64 | } 65 | 66 | if (mappingDetail[key] === "" && key === "AadRoleName") { 67 | state.error["aadRoleName"] = true; 68 | } 69 | else if (mappingDetail[key] !== "" && key === "AadRoleName") { 70 | state.error["aadRoleName"] = false; 71 | } 72 | 73 | if (key === "DnnRoleName") { 74 | mappingDetail[key] = event.value; 75 | } 76 | else { 77 | mappingDetail[key] = typeof (event) === "object" ? event.target.value : event; 78 | } 79 | 80 | this.setState({ 81 | mappingDetail: mappingDetail, 82 | triedToSubmit: false, 83 | error: state.error 84 | }); 85 | 86 | props.dispatch(SettingsActions.roleMappingClientModified(mappingDetail)); 87 | } 88 | 89 | getRolePropertyOptions() { 90 | let options = []; 91 | 92 | if (this.props.availableRoles !== undefined) { 93 | options = this.props.availableRoles.map((item) => { 94 | return { label: item, value: item }; 95 | }); 96 | } 97 | return options; 98 | } 99 | 100 | onSave() { 101 | const {props, state} = this; 102 | this.setState({ 103 | triedToSubmit: true 104 | }); 105 | if (state.error.dnnRoleName || state.error.aadRoleName) { 106 | return; 107 | } 108 | 109 | props.onUpdate(state.mappingDetail); 110 | props.Collapse(); 111 | } 112 | 113 | onCancel() { 114 | const {props} = this; 115 | 116 | if (props.mappingClientModified) { 117 | util.utilities.confirm(resx.get("SettingsRestoreWarning"), resx.get("Yes"), resx.get("No"), () => { 118 | props.dispatch(SettingsActions.cancelRoleMappingClientModified()); 119 | props.Collapse(); 120 | }); 121 | } 122 | else { 123 | props.Collapse(); 124 | } 125 | } 126 | 127 | /* eslint-disable react/no-danger */ 128 | render() { 129 | if (this.state.mappingDetail !== undefined || this.props.id === "add") { 130 | const columnOne =
    131 | 132 | 143 | 144 |
    ; 145 | const columnTwo =
    146 | 147 | 157 | 158 |
    ; 159 | 160 | return ( 161 |
    162 | {[columnOne, columnTwo]} 163 |
    164 | 169 | 174 |
    175 |
    176 | ); 177 | } 178 | else return
    ; 179 | } 180 | } 181 | 182 | RoleMappingEditor.propTypes = { 183 | dispatch: PropTypes.func.isRequired, 184 | mappingDetail: PropTypes.object, 185 | mappingId: PropTypes.string, 186 | dnnRoleName: PropTypes.string, 187 | aadRoleName: PropTypes.string, 188 | Collapse: PropTypes.func, 189 | onUpdate: PropTypes.func, 190 | id: PropTypes.string, 191 | mappingClientModified: PropTypes.bool, 192 | availableRoles: PropTypes.array, 193 | onValidate: PropTypes.func 194 | }; 195 | 196 | function mapStateToProps() { 197 | return { 198 | // profileMappingDetail: state.siteBehavior.aliasDetail, 199 | // profileMappingClientModified: state.siteBehavior.siteAliasClientModified 200 | }; 201 | } 202 | 203 | export default connect(mapStateToProps)(RoleMappingEditor); -------------------------------------------------------------------------------- /DotNetNuke.Authentication.Azure/Services/AzureADProviderSettings.cs: -------------------------------------------------------------------------------- 1 | #region Copyright 2 | 3 | // 4 | // Intelequia Software solutions - https://intelequia.com 5 | // Copyright (c) 2010-2017 6 | // by Intelequia Software Solutions 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 9 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 11 | // to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions 14 | // of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | // DEALINGS IN THE SOFTWARE. 21 | 22 | #endregion 23 | 24 | using System.Runtime.Serialization; 25 | using DotNetNuke.Authentication.Azure.Components; 26 | 27 | namespace DotNetNuke.Authentication.Azure.Services 28 | { 29 | [DataContract] 30 | public class AzureADProviderSettings 31 | { 32 | [DataMember(Name = "tenantId")] 33 | public string TenantId { get; set; } 34 | [DataMember(Name = "apiKey")] 35 | public string ApiKey { get; set; } 36 | [DataMember(Name = "apiSecret")] 37 | public string ApiSecret { get; set; } 38 | [DataMember(Name = "redirectUri")] 39 | public string RedirectUri { get; set; } 40 | [DataMember(Name = "onErrorUri")] 41 | public string OnErrorUri { get; set; } 42 | [DataMember(Name = "autoRedirect")] 43 | public bool AutoRedirect { get; set; } 44 | [DataMember(Name = "enabled")] 45 | public bool Enabled { get; set; } 46 | [DataMember(Name = "useGlobalSettings")] 47 | public bool UseGlobalSettings { get; set; } 48 | [DataMember(Name = "aadTenantId")] 49 | public string AadTenantId { get; set; } 50 | [DataMember(Name = "aadAppClientId")] 51 | public string AadAppClientId { get; set; } 52 | [DataMember(Name = "aadAppSecret")] 53 | public string AadAppSecret { get; set; } 54 | [DataMember(Name = "graphUseCustomParams")] 55 | public bool GraphUseCustomParams { get; set; } 56 | [DataMember(Name = "jwtAudiences")] 57 | public string JwtAudiences { get; set; } 58 | [DataMember(Name = "roleSyncEnabled")] 59 | public bool RoleSyncEnabled { get; set; } 60 | [DataMember(Name = "userSyncEnabled")] 61 | public bool UserSyncEnabled { get; set; } 62 | [DataMember(Name = "profileSyncEnabled")] 63 | public bool ProfileSyncEnabled { get; set; } 64 | [DataMember(Name = "apiResource")] 65 | public string ApiResource { get; set; } 66 | [DataMember(Name = "scopes")] 67 | public string Scopes { get; set; } 68 | [DataMember(Name = "usernamePrefixEnabled")] 69 | public bool UsernamePrefixEnabled { get; set; } 70 | [DataMember(Name = "groupNamePrefixEnabled")] 71 | public bool GroupNamePrefixEnabled { get; set; } 72 | [DataMember(Name = "autoAuthorize")] 73 | public bool AutoAuthorize { get; set; } 74 | [DataMember(Name = "authorizationCodePrompt")] 75 | public string AuthorizationCodePrompt { set; get; } 76 | [DataMember(Name = "domainHint")] 77 | public string DomainHint { get; set; } 78 | [DataMember(Name = "autoMatchExistingUsers")] 79 | public bool AutoMatchExistingUsers { get; set; } 80 | 81 | 82 | 83 | public static AzureADProviderSettings LoadSettings(string service, int portalId) 84 | { 85 | var config = new AzureConfig(service, portalId); 86 | return new AzureADProviderSettings 87 | { 88 | TenantId = config.TenantId, 89 | ApiKey = config.APIKey, 90 | ApiSecret = config.APISecret, 91 | RedirectUri = config.RedirectUri, 92 | OnErrorUri = config.OnErrorUri, 93 | AutoRedirect = config.AutoRedirect, 94 | AutoAuthorize = config.AutoAuthorize, 95 | AutoMatchExistingUsers = config.AutoMatchExistingUsers, 96 | AadTenantId = config.AADTenantId, 97 | AadAppClientId = config.AADApplicationId, 98 | AadAppSecret = config.AADApplicationKey, 99 | GraphUseCustomParams = config.GraphUseCustomParams, 100 | Enabled = config.Enabled, 101 | UseGlobalSettings = config.UseGlobalSettings, 102 | JwtAudiences = config.JwtAudiences, 103 | RoleSyncEnabled = config.RoleSyncEnabled, 104 | UserSyncEnabled = config.UserSyncEnabled, 105 | ProfileSyncEnabled = config.ProfileSyncEnabled, 106 | ApiResource = config.APIResource, 107 | Scopes = config.Scopes, 108 | UsernamePrefixEnabled = config.UsernamePrefixEnabled, 109 | GroupNamePrefixEnabled = config.GroupNamePrefixEnabled, 110 | AuthorizationCodePrompt = config.AuthorizationCodePrompt, 111 | DomainHint = config.DomainHint 112 | }; 113 | } 114 | 115 | public static void SaveGeneralSettings(string service, int portalId, AzureADProviderSettings settings) 116 | { 117 | var config = new AzureConfig(service, portalId) 118 | { 119 | TenantId = settings.TenantId, 120 | APIKey = settings.ApiKey, 121 | APISecret = settings.ApiSecret, 122 | RedirectUri = settings.RedirectUri, 123 | OnErrorUri = settings.OnErrorUri, 124 | AutoRedirect = settings.AutoRedirect, 125 | AutoAuthorize = settings.AutoAuthorize, 126 | AutoMatchExistingUsers = settings.AutoMatchExistingUsers, 127 | Enabled = settings.Enabled, 128 | UseGlobalSettings = settings.UseGlobalSettings 129 | }; 130 | 131 | AzureConfig.UpdateConfig(config); 132 | } 133 | 134 | public static void SaveAdvancedSyncSettings(string service, int portalId, AzureADProviderSettings settings) 135 | { 136 | var config = new AzureConfig(service, portalId) 137 | { 138 | AADTenantId = settings.AadTenantId, 139 | AADApplicationId = settings.AadAppClientId, 140 | AADApplicationKey = settings.AadAppSecret, 141 | GraphUseCustomParams = settings.GraphUseCustomParams, 142 | RoleSyncEnabled = settings.RoleSyncEnabled, 143 | UserSyncEnabled = settings.UserSyncEnabled, 144 | ProfileSyncEnabled = settings.ProfileSyncEnabled, 145 | UsernamePrefixEnabled = settings.UsernamePrefixEnabled, 146 | GroupNamePrefixEnabled = settings.GroupNamePrefixEnabled 147 | }; 148 | 149 | AzureConfig.UpdateConfig(config); 150 | } 151 | public static void SaveAdvancedMoreSettings(string service, int portalId, AzureADProviderSettings settings) 152 | { 153 | var config = new AzureConfig(service, portalId) 154 | { 155 | JwtAudiences = settings.JwtAudiences, 156 | APIResource = settings.ApiResource + (!string.IsNullOrEmpty(settings.ApiResource.Trim()) && !settings.ApiResource.EndsWith("/") ? "/" : ""), 157 | Scopes = settings.Scopes, 158 | AuthorizationCodePrompt = settings.AuthorizationCodePrompt, 159 | DomainHint = settings.DomainHint 160 | }; 161 | 162 | AzureConfig.UpdateConfig(config); 163 | } 164 | } 165 | } 166 | --------------------------------------------------------------------------------