diff options
Diffstat (limited to 'sdnr/wireless-transport/code-Carbon-SR1/ux/security')
15 files changed, 813 insertions, 0 deletions
diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/pom.xml b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/pom.xml new file mode 100644 index 00000000..8973079b --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/pom.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>com.highstreet.technologies.odl.dlux</groupId> + <artifactId>mwtn</artifactId> + <version>0.5.1-SNAPSHOT</version> + <relativePath>../</relativePath> + </parent> + + <groupId>org.onap.sdnc.dluxapps</groupId> + <artifactId>security</artifactId> + <!-- <name> formatting is used by autorelease to parse and notify projects on + build failure. Please do not modify this unless you have a good reason. --> + <name>${prefix} ${project.artifactId}</name> + <version>0.5.1</version> + <packaging>pom</packaging> + + <prerequisites> + <maven>3.0</maven> + </prerequisites> + + <modules> + <module>security-module</module> + <module>security-bundle</module> + </modules> +</project> diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/pom.xml b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/pom.xml new file mode 100644 index 00000000..34358bbe --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/pom.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.sdnc.dluxapps</groupId> + <artifactId>security</artifactId> + <version>0.5.1</version> + </parent> + + <groupId>org.onap.sdnc.dluxapps</groupId> + <artifactId>security-bundle</artifactId> + <packaging>bundle</packaging> + <!-- <name> formatting is used by autorelease to parse and notify projects on + build failure. Please do not modify this unless you have a good reason. --> + <name>${prefix} ${project.artifactId}</name> + + <dependencies> + <dependency> + <groupId>org.opendaylight.dlux</groupId> + <artifactId>loader</artifactId> + <version>0.5.1-Carbon</version> + </dependency> + <dependency> + <groupId>org.onap.sdnc.dluxapps</groupId> + <artifactId>security-module</artifactId> + <version>0.5.1</version> + <scope>provided</scope> + </dependency> + </dependencies> + <build> + <resources> + <resource> + <directory>target/generated-resources</directory> + </resource> + <resource> + <directory>src/main/resources</directory> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <!--loader Resources--> + <execution> + <id>unpack-loader-resources</id> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <phase>generate-resources</phase> + <configuration> + <outputDirectory>${project.build.directory}/generated-resources</outputDirectory> + <groupId>org.onap.sdnc.dluxapps</groupId> + <includeArtifactIds>security-module</includeArtifactIds> + <!-- <includes>security/src\/**</includes> --> + <excludes>META-INF\/**</excludes> + <excludeTransitive>true</excludeTransitive> + <ignorePermissions>false</ignorePermissions> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Import-Package>org.osgi.service.http, + org.osgi.framework;version="1.0.0", + org.opendaylight.dlux.loader + </Import-Package> + <Export-Package></Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 00000000..65ef78a3 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,19 @@ +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> + <reference id="httpService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService"/> + <reference id="loader" availability="mandatory" activation="eager" interface="org.opendaylight.dlux.loader.DluxModuleLoader"/> + + <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.opendaylight.dlux.loader.DluxModule"> + <property name="httpService" ref="httpService"/> + <property name="loader" ref="loader"/> + <property name="moduleName" value="security"/> + <property name="url" value="/src/app/security"/> + <property name="directory" value="/security/src"/> + <property name="requireJs" value="app/security/security.module"/> + <property name="angularJs" value="app.security"/> + <property name="cssDependencies"> + <list> + <value>src/app/security/security.custom.css</value> + </list> + </property> + </bean> +</blueprint> diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/pom.xml b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/pom.xml new file mode 100644 index 00000000..95ae27b2 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/pom.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>security</artifactId> + <groupId>org.onap.sdnc.dluxapps</groupId> + <version>0.5.1</version> + <relativePath>../</relativePath> + </parent> + <groupId>org.onap.sdnc.dluxapps</groupId> + <artifactId>security-module</artifactId> + <name>${prefix} ${project.artifactId}</name> + <version>0.5.1</version> + <packaging>jar</packaging> + + </project> diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/build.config.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/build.config.js new file mode 100644 index 00000000..c8396a3f --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/build.config.js @@ -0,0 +1,42 @@ +/** + * This file/module contains all configuration for the build process. + */ +module.exports = { + build_dir: 'build', + app_dir: 'app', + + app_files: { + js: [ + 'src/*/**/*.js', + '!node/**/*.*', + '!node_modules/**/*.*', + '!src/vendor/**/*.*' + ], + root_js: [ + 'src/*.js' + ], + less: [ + 'src/assets/less/*.less' + ], + img: [ + 'src/assets/img/*.*' + ], + + templates: [ + 'src/*/**/*.tpl.html', + 'src/*.tpl.html' + ] + }, + + assets_files: { + less: [], + css: [], + data: [] + }, + + vendor_files: { + js: [], + css: [], + fonts: [] + } +}; diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/gulpfile.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/gulpfile.js new file mode 100644 index 00000000..c3a15c45 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/gulpfile.js @@ -0,0 +1,142 @@ +var gulp = require('gulp'), + del = require('del'), + gutil = require('gulp-util'), + concat = require('gulp-concat'), + runSequence = require('run-sequence'), + install = require("gulp-install"), + connect = require('gulp-connect'), + open = require('gulp-open'), + argv = require('yargs').argv, + less = require('gulp-less'), + debug = require('gulp-debug'), + replace = require('gulp-replace-task'); + +var config = require( './build.config.js'); + + +/** + * Task for cleaning build directory + */ +gulp.task('clean', function() { + // You can use multiple globbing patterns as you would with `gulp.src` + return del(config.build_dir); +}); + +/** + * Copy assets + */ +gulp.task('copyAssetsCss', function () { + return gulp.src(config.assets_files.css) + .pipe( + gulp.dest( + (config.build_dir) + '/assets/css' + ) + ); +}); + +gulp.task('copyAssetsData', function () { + return gulp.src(config.assets_files.data) + .pipe(gulp.dest((config.build_dir) + '/assets/data')); +}); + +/** + * Copy app files + */ +gulp.task('copyTemplates', function () { + gutil.log(gutil.colors.cyan('INFO :: copying APP Template files')); + // Copy html + return gulp.src(config.app_files.templates) + .pipe(gulp.dest(config.build_dir)); +}); + +gulp.task('copyAppJs', function () { + gutil.log(gutil.colors.cyan('INFO :: copying APP Controller JS files')); + return gulp.src(config.app_files.js) + .pipe(gulp.dest(config.build_dir)); +}); + +gulp.task('copyRootJs', function () { + gutil.log(gutil.colors.cyan('INFO :: copying APP Root JS files')); + return gulp.src(config.app_files.root_js) + .pipe(gulp.dest(config.build_dir)); +}); + +/** + * Compile css from less files + */ +gulp.task('less', function () { + gutil.log(gutil.colors.cyan('INFO :: compiling LESS file')); + return gulp.src(config.app_files.less) + .pipe(less()) + .pipe(gulp.dest((config.build_dir) + '/assets/css')); +}); + +/** + * Copy app assets images + */ +gulp.task('copyAppImgs', function () { + gutil.log(gutil.colors.cyan('INFO :: copying image files')); + return gulp.src(config.app_files.img) + .pipe(gulp.dest((config.build_dir) + '/assets/img')); + +}); + +/** + * Copy vendor files + */ +gulp.task('copyVendorCss', function () { + gutil.log(gutil.colors.cyan('INFO :: copying VENDOR css')); + return gulp.src(config.vendor_files.css, { cwd : 'node_modules/**' }) + .pipe(gulp.dest((config.build_dir) + '/vendor')); +}); + +gulp.task('copyVendorFonts', function () { + gutil.log(gutil.colors.cyan('INFO :: copying VENDOR fonts')); + return gulp.src(config.vendor_files.fonts, { cwd : 'node_modules/**' }) + .pipe(gulp.dest((config.build_dir) + '/vendor')); +}); + +gulp.task('copyVendorJs', function () { + gutil.log(gutil.colors.cyan('INFO :: copying VENDOR js files')); + return gulp.src(config.vendor_files.js, { cwd : 'node_modules/**' }) + .pipe(gulp.dest((config.build_dir) + '/vendor')); +}); + +/** + * Copy task aggregated + */ +gulp.task('copy', function() { + runSequence('less', [ + 'copyAssetsCss', + 'copyAssetsData', + 'copyTemplates', + 'copyAppJs', + 'copyRootJs', + 'copyVendorCss', + 'copyVendorFonts', + 'copyAppImgs' + ], 'copyVendorJs'); +}); + +/** + * Build task + */ +gulp.task('build', function(){ + runSequence('clean', 'copy'); +}); + + +/** + * Live preview main task for development + * argument --live should be used to force build task to build only live preview + */ +gulp.task('default', function (){ + + if (!argv.live) { + gutil.log(gutil.colors.red('ERROR :: --live argument must be used for live preview!')); + } + + gutil.log(gutil.colors.cyan('INFO :: opening new browser tab live:' + argv.live)); + + runSequence('build'); +}); diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/package.json b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/package.json new file mode 100644 index 00000000..2fb0b713 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/package.json @@ -0,0 +1,29 @@ +{ + "name": "odl-dluxapps-security", + "version": "0.5.1", + "main": "main.js", + "devDependencies": { + "gulp-bower": "0.0.13" + }, + "dependencies": { + "del": "^2.2.0", + "gulp": "^3.9.1", + "gulp-concat": "^2.6.0", + "gulp-connect": "^5.0.0", + "gulp-debug": "^3.0.0", + "gulp-install": "^0.6.0", + "gulp-less": "^3.1.0", + "gulp-open": "^2.0.0", + "gulp-replace-task": "^0.11.0", + "gulp-util": "^3.0.7", + "run-sequence": "^1.1.5" + }, + "repository": { + "type": "git", + "url": "https://git.opendaylight.org/gerrit/dluxapps" + }, + "license": "EPL", + "keywords": [ + "odl" + ] +} diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.js new file mode 100644 index 00000000..e7f12c22 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.js @@ -0,0 +1,149 @@ +define("security.service", ["require", "exports", "angularAMD"], function (require, exports, angular) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var security = angular.module('app.security'); + var SecurityService = /** @class */ (function () { + function SecurityService($q, $http, $window, env) { + this.$q = $q; + this.$http = $http; + this.$window = $window; + this.env = env; + this.ensureCrendentials(); + } + SecurityService.prototype.ensureCrendentials = function () { + var credentialsDefer = this.$q.defer(); + this.credentials = credentialsDefer.promise; + var url = this.env.getBaseURL('MD_SAL') + "/oauth2/token"; + this.$http({ + method: "POST", + url: url, + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + data: "grant_type=password&username=" + this.$window.sessionStorage.odlUser + "&password=" + this.$window.sessionStorage.odlPass + "&scope=sdn" + }).then(function (res) { + credentialsDefer.resolve(res.data && res.data.access_token); + }, function (err) { + credentialsDefer.reject(err); + }); + }; + Object.defineProperty(SecurityService.prototype, "token", { + get: function () { + return this.credentials; + }, + enumerable: true, + configurable: true + }); + SecurityService.prototype.getAllUsers = function () { + var _this = this; + var url = this.env.getBaseURL('MD_SAL') + "/auth/v1/users"; + return this.token.then(function (token) { + return _this.$http({ + method: "GET", + url: url, + headers: { 'Authorization': "Bearer " + token } + }).then(function (result) { return result.data && result.data.users; }); + }); + }; + SecurityService.prototype.getAllRoles = function () { + var _this = this; + var url = this.env.getBaseURL('MD_SAL') + "/auth/v1/roles"; + return this.token.then(function (token) { + return _this.$http({ + method: "GET", + url: url, + headers: { 'Authorization': "Bearer " + token } + }).then(function (result) { return result.data && result.data.roles; }); + }); + }; + SecurityService.prototype.getUserById = function (userId) { + var _this = this; + var url = this.env.getBaseURL('MD_SAL') + "/auth/v1/users/" + userId; + return this.token.then(function (token) { + return _this.$http({ + method: "GET", + url: url, + headers: { 'Authorization': "Bearer " + token } + }).then(function (result) { return result.data && result.data; }); + }); + }; + SecurityService.prototype.getRolesForDomainUser = function (userId, domain) { + var _this = this; + if (domain === void 0) { domain = "sdn"; } + var url = this.env.getBaseURL('MD_SAL') + "/auth/v1/domains/" + domain + "/users/" + userId + "/roles"; + return this.token.then(function (token) { + return _this.$http({ + method: "GET", + url: url, + headers: { 'Authorization': "Bearer " + token } + }).then(function (result) { return result.data && result.data.roles; }); + }); + }; + return SecurityService; + }()); + exports.SecurityService = SecurityService; + security.service('securityService', ['$q', '$http', '$window', 'ENV', SecurityService]); +}); +define( ["require", "exports", "security.service"], function (require, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + var security = angular.module('app.security'); + var UserDetailsCtrl = /** @class */ (function () { + function UserDetailsCtrl($scope, $uibModalInstance, userid, roles) { + var _this = this; + this.$uibModalInstance = $uibModalInstance; + this.userid = userid; + this.roles = roles; + this.ok = function () { + _this.$uibModalInstance.close( /* Parameter*/); + }; + this.cancel = function () { + _this.$uibModalInstance.dismiss('cancel'); + }; + } + return UserDetailsCtrl; + }()); + security.controller('userDetailsCtrl', ['$scope', '$uibModalInstance', 'userid', 'roles', UserDetailsCtrl]); + var SecurityCtrl = /** @class */ (function () { + function SecurityCtrl($scope, $timeout, $q, $uibModal, $document, $mwtnCommons, securityService) { + this.$q = $q; + this.$uibModal = $uibModal; + this.$document = $document; + this.securityService = securityService; + $scope.message = "Empty"; + $scope.users = []; + $scope.roles = []; + $scope.currentUser = {}; + $scope.getCurrentUserById = function (id) { + id !== null && securityService.getRolesForDomainUser(id).then(function (roles) { + var parentElem = angular.element($document[0].querySelector('#security')); + var modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/security/templates/userDetails.html', + controller: 'userDetailsCtrl', + controllerAs: 'vm', + appendTo: parentElem, + size: 'sm', + resolve: { + roles: function () { return roles; }, + userid: function () { return id; }, + } + }); + }); + }; + securityService.token.then(function (res) { + $q.all([ + securityService.getAllUsers(), + securityService.getAllRoles() + ]).then(function (_a) { + var users = _a[0], roles = _a[1]; + $scope.users = users; + $scope.roles = roles; + }); + }); + } + return SecurityCtrl; + }()); + security.controller('securityCtrl', ['$scope', '$timeout', '$q', '$uibModal', '$document', '$mwtnCommons', 'securityService', SecurityCtrl]); +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJpdHkuY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNyYy9hcHAvc2VjdXJpdHkvc2VjdXJpdHkuc2VydmljZS50cyIsInNyYy9hcHAvc2VjdXJpdHkvc2VjdXJpdHkuY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7SUFFQSxJQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBdUJoRDtRQUdFLHlCQUFvQixFQUFnQixFQUFVLEtBQXNCLEVBQVUsT0FBTyxFQUFVLEdBQWdCO1lBQTNGLE9BQUUsR0FBRixFQUFFLENBQWM7WUFBVSxVQUFLLEdBQUwsS0FBSyxDQUFpQjtZQUFVLFlBQU8sR0FBUCxPQUFPLENBQUE7WUFBVSxRQUFHLEdBQUgsR0FBRyxDQUFhO1lBQzdHLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzVCLENBQUM7UUFFTyw0Q0FBa0IsR0FBMUI7WUFDRSxJQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFVLENBQUM7WUFDakQsSUFBSSxDQUFDLFdBQVcsR0FBRyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7WUFFNUMsSUFBTSxHQUFHLEdBQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLGtCQUFlLENBQUM7WUFDNUQsSUFBSSxDQUFDLEtBQUssQ0FBMkI7Z0JBQ25DLE1BQU0sRUFBRSxNQUFNO2dCQUNkLEdBQUcsRUFBRSxHQUFHO2dCQUNSLE9BQU8sRUFBRSxFQUFFLGNBQWMsRUFBRSxtQ0FBbUMsRUFBRTtnQkFDaEUsSUFBSSxFQUFFLGtDQUFnQyxJQUFJLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxPQUFPLGtCQUFhLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLE9BQU8sZUFBWTthQUN0SSxDQUFDLENBQUMsSUFBSSxDQUFDLFVBQUEsR0FBRztnQkFDVCxnQkFBZ0Is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ZSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBQSxHQUFHO2dCQUM1QixFQUFFLENBQUMsR0FBRyxDQUFDO29CQUNMLGVBQWUsQ0FBQyxXQUFXLEVBQUU7b0JBQzdCLGVBQWUsQ0FBQyxXQUFXLEVBQUU7aUJBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFDLEVBQWM7d0JBQWIsYUFBSyxFQUFFLGFBQUs7b0JBQ2pELE1BQU0sQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO29CQUNyQixNQUFNLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztnQkFDekIsQ0FBQyxDQUFDLENBQUE7WUFDSixDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDSCxtQkFBQztJQUFELENBQUMsQUFwQ0QsSUFvQ0M7SUFFRCxRQUFRLENBQUMsVUFBVSxDQUFDLGNBQWMsRUFBRSxDQUFDLFFBQVEsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBQyxXQUFXLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLFlBQVksQ0FBRSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBhbmd1bGFyIGZyb20gJ2FuZ3VsYXJBTUQnO1xuXG5jb25zdCBzZWN1cml0eSA9IGFuZ3VsYXIubW9kdWxlKCdhcHAuc2VjdXJpdHknKTtcblxuaW50ZXJmYWNlIElFbnZTZXJ2aWNlIHtcbiAgZ2V0QmFzZVVSTChwb3J0OiBzdHJpbmcpOiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIFVzZXIgPSB7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIGRvbWFpbmlkOiBzdHJpbmc7XG4gIGVtYWlsOiBzdHJpbmc7XG4gIGVuYWJsZWQ6IGJvb2xlYW47XG4gIHBhc3N3b3JkOiBzdHJpbmc7XG4gIHNhbHQ6IHN0cmluZztcbiAgdXNlcmlkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIFJvbGUgPSB7XG4gIHJvbGVpZDogc3RyaW5nO1xuICBuYW1lOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIGRvbWFpbmlkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBTZWN1cml0eVNlcnZpY2Uge1xuICBwcml2YXRlIGNyZWRlbnRpYWxzOiBuZy5JUHJvbWlzZTxzdHJpbmc+O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgJHE6IG5nLklRU2VydmljZSwgcHJpdmF0ZSAkaHR0cDogbmcuSUh0dHBTZXJ2aWNlLCBwcml2YXRlICR3aW5kb3csIHByaXZhdGUgZW52OiBJRW52U2VydmljZSkge1xuICAgIHRoaXMuZW5zdXJlQ3JlbmRlbnRpYWxzKCk7XG4gIH1cblxuICBwcml2YXRlIGVuc3VyZUNyZW5kZW50aWFscygpIHtcbiAgICBjb25zdCBjcmVkZW50aWFsc0RlZmVyID0gdGhpcy4kcS5kZWZlcjxzdHJpbmc+KCk7XG4gICAgdGhpcy5jcmVkZW50aWFscyA9IGNyZWRlbnRpYWxzRGVmZXIucHJvbWlzZTtcblxuICAgIGNvbnN0IHVybCA9IGAke3RoaXMuZW52LmdldEJhc2VVUkwoJ01EX1NBTCcpfS9vYXV0aDIvdG9rZW5gO1xuICAgIHRoaXMuJGh0dHA8eyBhY2Nlc3NfdG9rZW46IHN0cmluZyB9Pih7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgdXJsOiB1cmwsXG4gICAgICBoZWFkZXJzOiB7ICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJyB9LFxuICAgICAgZGF0YTogYGdyYW50X3R5cGU9cGFzc3dvcmQmdXNlcm5hbWU9JHt0aGlzLiR3aW5kb3cuc2Vzc2lvblN0b3JhZ2Uub2RsVXNlcn0mcGFzc3dvcmQ9JHt0aGlzLiR3aW5kb3cuc2Vzc2lvblN0b3JhZ2Uub2RsUGFzc30mc2NvcGU9c2RuYFxuICAgIH0pLnRoZW4ocmVzID0+IHtcbiAgICAgIGNyZWRlbnRpYWxzRGVmZXIucmVzb2x2ZShyZXMuZGF0YSAmJiByZXMuZGF0YS5hY2Nlc3NfdG9rZW4pO1xuICAgIH0sIGVyciA9PiB7XG4gICAgICBjcmVkZW50aWFsc0RlZmVyLnJlamVjdChlcnIpO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGdldCB0b2tlbigpIHtcbiAgICByZXR1cm4gdGhpcy5jcmVkZW50aWFscztcbiAgfVxuXG4gIHB1YmxpYyBnZXRBbGxVc2VycygpOiBuZy5JUHJvbWlzZTxVc2VyW10+IHtcbiAgICBjb25zdCB1cmwgPSBgJHt0aGlzLmVudi5nZXRCYXNlVVJMKCdNRF9TQUwnKX0vYXV0aC92MS91c2Vyc2A7XG4gICAgcmV0dXJuIHRoaXMudG9rZW4udGhlbih0b2tlbiA9PiB7XG4gICAgICByZXR1cm4gdGhpcy4kaHR0cDx7IHVzZXJzOiBVc2VyW10gfT4oe1xuICAgICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICAgIHVybDogdXJsLFxuICAgICAgICBoZWFkZXJzOiB7ICdBdXRob3JpemF0aW9uJzogYEJlYXJlciAke3Rva2VufWAgfVxuICAgICAgfSkudGhlbihyZXN1bHQgPT4gcmVzdWx0LmRhdGEgJiYgcmVzdWx0LmRhdGEudXNlcnMpXG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgZ2V0QWxsUm9sZXMoKTogbmcuSVByb21pc2U8Um9sZVtdPiB7XG4gICAgY29uc3QgdXJsID0gYCR7dGhpcy5lbnYuZ2V0QmFzZVVSTCgnTURfU0FMJyl9L2F1dGgvdjEvcm9sZXNgO1xuICAgIHJldHVybiB0aGlzLnRva2VuLnRoZW4odG9rZW4gPT4ge1xuICAgICAgcmV0dXJuIHRoaXMuJGh0dHA8eyByb2xlczogUm9sZVtdIH0+KHtcbiAgICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgICB1cmw6IHVybCxcbiAgICAgICAgaGVhZGVyczogeyAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHt0b2tlbn1gIH1cbiAgICAgIH0pLnRoZW4ocmVzdWx0ID0+IHJlc3VsdC5kYXRhICYmIHJlc3VsdC5kYXRhLnJvbGVzKVxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGdldFVzZXJCeUlkKHVzZXJJZDogc3RyaW5nKTogbmcuSVByb21pc2U8VXNlcj4ge1xuICAgIGNvbnN0IHVybCA9IGAke3RoaXMuZW52LmdldEJhc2VVUkwoJ01EX1NBTCcpfS9hdXRoL3YxL3VzZXJzLyR7dXNlcklkfWA7XG4gICAgcmV0dXJuIHRoaXMudG9rZW4udGhlbih0b2tlbiA9PiB7XG4gICAgICByZXR1cm4gdGhpcy4kaHR0cDxVc2VyPih7XG4gICAgICAgIG1ldGhvZDogXCJHRVRcIixcbiAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgIGhlYWRlcnM6IHsgJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyICR7dG9rZW59YCB9XG4gICAgICB9KS50aGVuKHJlc3VsdCA9PiByZXN1bHQuZGF0YSAmJiByZXN1bHQuZGF0YSlcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRSb2xlc0ZvckRvbWFpblVzZXIodXNlcklkOiBzdHJpbmcsIGRvbWFpbjogc3RyaW5nPSBcInNkblwiKTogbmcuSVByb21pc2U8Um9sZVtdPiB7XG4gICAgY29uc3QgdXJsID0gYCR7dGhpcy5lbnYuZ2V0QmFzZVVSTCgnTURfU0FMJyl9L2F1dGgvdjEvZG9tYWlucy8ke2RvbWFpbn0vdXNlcnMvJHt1c2VySWR9L3JvbGVzYDtcbiAgICByZXR1cm4gdGhpcy50b2tlbi50aGVuKHRva2VuID0+IHtcbiAgICAgIHJldHVybiB0aGlzLiRodHRwPHsgcm9sZXM6IFJvbGVbXSB9Pih7XG4gICAgICAgIG1ldGhvZDogXCJHRVRcIixcbiAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgIGhlYWRlcnM6IHsgJ0F1dGhvcml6YXRpb24nOiBgQmVhcmVyICR7dG9rZW59YCB9XG4gICAgICB9KS50aGVuKHJlc3VsdCA9PiByZXN1bHQuZGF0YSAmJiByZXN1bHQuZGF0YS5yb2xlcylcbiAgICB9KTtcbiAgfVxufVxuXG5zZWN1cml0eS5zZXJ2aWNlKCdzZWN1cml0eVNlcnZpY2UnLCBbJyRxJywgJyRodHRwJywgJyR3aW5kb3cnLCAnRU5WJywgU2VjdXJpdHlTZXJ2aWNlXSk7IiwiZGVjbGFyZSB2YXIgYW5ndWxhcjogYW5ndWxhci5JQW5ndWxhclN0YXRpYzsgXG5cbmltcG9ydCB7IFNlY3VyaXR5U2VydmljZSwgUm9sZSB9IGZyb20gXCIuL3NlY3VyaXR5LnNlcnZpY2VcIjsgXG5cbmltcG9ydCBcIi4vc2VjdXJpdHkuc2VydmljZVwiO1xuXG5jb25zdCBzZWN1cml0eSA9IGFuZ3VsYXIubW9kdWxlKCdhcHAuc2VjdXJpdHknKTtcblxuY2xhc3MgVXNlckRldGFpbHNDdHJsIHtcbiAgY29uc3RydWN0b3IoJHNjb3BlLCBwcml2YXRlICR1aWJNb2RhbEluc3RhbmNlLCBwdWJsaWMgdXNlcmlkOiBzdHJpbmcsIHB1YmxpYyByb2xlczogUm9sZVtdKSB7XG5cbiAgfVxuXG4gIHB1YmxpYyBvayA9ICgpID0+IHtcbiAgICB0aGlzLiR1aWJNb2RhbEluc3RhbmNlLmNsb3NlKC8qIFBhcmFtZXRlciovKTtcbiAgfTtcblxuICBwdWJsaWMgY2FuY2VsID0gKCkgPT4ge1xuICAgIHRoaXMuJHVpYk1vZGFsSW5zdGFuY2UuZGlzbWlzcygnY2FuY2VsJyk7XG4gIH07XG59XG5cbnNlY3VyaXR5LmNvbnRyb2xsZXIoJ3VzZXJEZXRhaWxzQ3RybCcsIFsnJHNjb3BlJywgJyR1aWJNb2RhbEluc3RhbmNlJywgJ3VzZXJpZCcsICdyb2xlcycsIFVzZXJEZXRhaWxzQ3RybF0pO1xuXG5jbGFzcyBTZWN1cml0eUN0cmwge1xuICBjb25zdHJ1Y3Rvcigkc2NvcGUsICR0aW1lb3V0LCBwcml2YXRlICRxOiBuZy5JUVNlcnZpY2UsIHByaXZhdGUgJHVpYk1vZGFsLCBwcml2YXRlICRkb2N1bWVudCA6IG5nLklEb2N1bWVudFNlcnZpY2UsICAkbXd0bkNvbW1vbnMsIHByaXZhdGUgc2VjdXJpdHlTZXJ2aWNlOiBTZWN1cml0eVNlcnZpY2UpIHtcbiAgICAkc2NvcGUubWVzc2FnZSA9IFwiRW1wdHlcIjtcbiAgICAkc2NvcGUudXNlcnMgPSBbXTtcbiAgICAkc2NvcGUucm9sZXMgPSBbXTtcbiAgICAkc2NvcGUuY3VycmVudFVzZXIgPSB7fTtcblxuICAgICRzY29wZS5nZXRDdXJyZW50VXNlckJ5SWQgPSBmdW5jdGlvbiAoaWQ6IHN0cmluZykge1xuICAgICAgaWQgIT09IG51bGwgJiYgc2VjdXJpdHlTZXJ2aWNlLmdldFJvbGVzRm9yRG9tYWluVXNlcihpZCkudGhlbihyb2xlcyA9PiB7XG4gICAgICAgIGNvbnN0IHBhcmVudEVsZW0gPSBhbmd1bGFyLmVsZW1lbnQoJGRvY3VtZW50WzBdLnF1ZXJ5U2VsZWN0b3IoJyNzZWN1cml0eScpKTtcbiAgICAgICAgY29uc3QgbW9kYWxJbnN0YW5jZSA9ICR1aWJNb2RhbC5vcGVuKHtcbiAgICAgICAgICBhbmltYXRpb246IHRydWUsXG4gICAgICAgICAgYXJpYUxhYmVsbGVkQnk6ICdtb2RhbC10aXRsZScsXG4gICAgICAgICAgYXJpYURlc2NyaWJlZEJ5OiAnbW9kYWwtYm9keScsXG4gICAgICAgICAgdGVtcGxhdGVVcmw6ICdzcmMvYXBwL3NlY3VyaXR5L3RlbXBsYXRlcy91c2VyRGV0YWlscy5odG1sJyxcbiAgICAgICAgICBjb250cm9sbGVyOiAndXNlckRldGFpbHNDdHJsJyxcbiAgICAgICAgICBjb250cm9sbGVyQXM6ICd2bScsXG4gICAgICAgICAgYXBwZW5kVG86IHBhcmVudEVsZW0sXG4gICAgICAgICAgc2l6ZTogJ3NtJyxcbiAgICAgICAgICByZXNvbHZlOiB7XG4gICAgICAgICAgICByb2xlczogKCkgPT4gcm9sZXMsXG4gICAgICAgICAgICB1c2VyaWQ6ICgpID0+IGlkLFxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfTsgIFxuXG4gICAgc2VjdXJpdHlTZXJ2aWNlLnRva2VuLnRoZW4ocmVzID0+IHtcbiAgICAgICRxLmFsbChbXG4gICAgICAgIHNlY3VyaXR5U2VydmljZS5nZXRBbGxVc2VycygpLFxuICAgICAgICBzZWN1cml0eVNlcnZpY2UuZ2V0QWxsUm9sZXMoKV0pLnRoZW4oKFt1c2Vycywgcm9sZXNdKSA9PiB7XG4gICAgICAgICAgJHNjb3BlLnVzZXJzID0gdXNlcnM7XG4gICAgICAgICAgJHNjb3BlLnJvbGVzID0gcm9sZXM7XG4gICAgICB9KVxuICAgIH0pO1xuICB9XG59XG5cbnNlY3VyaXR5LmNvbnRyb2xsZXIoJ3NlY3VyaXR5Q3RybCcsIFsnJHNjb3BlJywgJyR0aW1lb3V0JywgJyRxJywgJyR1aWJNb2RhbCcsJyRkb2N1bWVudCcsICckbXd0bkNvbW1vbnMnLCAnc2VjdXJpdHlTZXJ2aWNlJywgU2VjdXJpdHlDdHJsIF0pOyJdfQ==
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.ts b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.ts new file mode 100644 index 00000000..49315319 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.ts @@ -0,0 +1,63 @@ +declare var angular: angular.IAngularStatic; + +import { SecurityService, Role } from "./security.service"; + +import "./security.service"; + +const security = angular.module('app.security'); + +class UserDetailsCtrl { + constructor($scope, private $uibModalInstance, public userid: string, public roles: Role[]) { + + } + + public ok = () => { + this.$uibModalInstance.close(/* Parameter*/); + }; + + public cancel = () => { + this.$uibModalInstance.dismiss('cancel'); + }; +} + +security.controller('userDetailsCtrl', ['$scope', '$uibModalInstance', 'userid', 'roles', UserDetailsCtrl]); + +class SecurityCtrl { + constructor($scope, $timeout, private $q: ng.IQService, private $uibModal, private $document : ng.IDocumentService, $mwtnCommons, private securityService: SecurityService) { + $scope.message = "Empty"; + $scope.users = []; + $scope.roles = []; + $scope.currentUser = {}; + + $scope.getCurrentUserById = function (id: string) { + id !== null && securityService.getRolesForDomainUser(id).then(roles => { + const parentElem = angular.element($document[0].querySelector('#security')); + const modalInstance = $uibModal.open({ + animation: true, + ariaLabelledBy: 'modal-title', + ariaDescribedBy: 'modal-body', + templateUrl: 'src/app/security/templates/userDetails.html', + controller: 'userDetailsCtrl', + controllerAs: 'vm', + appendTo: parentElem, + size: 'sm', + resolve: { + roles: () => roles, + userid: () => id, + } + }) + }) + }; + + securityService.token.then(res => { + $q.all([ + securityService.getAllUsers(), + securityService.getAllRoles()]).then(([users, roles]) => { + $scope.users = users; + $scope.roles = roles; + }) + }); + } +} + +security.controller('securityCtrl', ['$scope', '$timeout', '$q', '$uibModal','$document', '$mwtnCommons', 'securityService', SecurityCtrl ]);
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.custom.css b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.custom.css new file mode 100644 index 00000000..67bd4579 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.custom.css @@ -0,0 +1,11 @@ +#security table > thead > tr > th { + background: #ddd +} + +#security table > tbody > tr > td { + background: #ddd +} + +#security table > tbody > tr:nth-child(odd) > td { + background: #eee +}
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.js b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.js new file mode 100644 index 00000000..dfd7e229 --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.js @@ -0,0 +1,33 @@ +define( ["require", "exports"], function (require, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.security = angular.module('app.security', ['app.core']); + exports.security.config(function ($stateProvider, $compileProvider, $controllerProvider, $provide, NavHelperProvider, $httpProvider, $translateProvider, $translatePartialLoaderProvider) { + //$translatePartialLoaderProvider.addPart('app/security/locale/locale'); + NavHelperProvider.addControllerUrl('app/security/security.controller'); + NavHelperProvider.addToMenu('security', { + "link": "#/security", + "active": "main.security", + "title": "Security", + "icon": "fa fa-shield", + "page": { + "title": "Security", + "description": "security" + } + }); + $stateProvider.state('main.security', { + url: 'security', + access: 2, + views: { + 'content': { + templateUrl: 'src/app/security/security.tpl.html', + controller: 'securityCtrl' + } + } + }); + }); +}); +/* non ES6 export */ +// export = security; +// export default security; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VjdXJpdHkubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3JjL2FwcC9zZWN1cml0eS9zZWN1cml0eS5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0lBR2EsUUFBQSxRQUFRLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRXJFLGdCQUFRLENBQUMsTUFBTSxDQUFDLFVBQVUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLG1CQUFtQixFQUFFLFFBQVEsRUFBRSxpQkFBaUIsRUFBRSxhQUFhLEVBQUUsa0JBQWtCLEVBQUUsK0JBQStCO1FBRTlLLHdFQUF3RTtRQUV4RSxpQkFBaUIsQ0FBQyxnQkFBZ0IsQ0FBQyxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ3ZFLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxVQUFVLEVBQUU7WUFDdEMsTUFBTSxFQUFFLFlBQVk7WUFDcEIsUUFBUSxFQUFFLGVBQWU7WUFDekIsT0FBTyxFQUFFLFVBQVU7WUFDbkIsTUFBTSxFQUFFLGVBQWU7WUFDdkIsTUFBTSxFQUFFO2dCQUNOLE9BQU8sRUFBRSxVQUFVO2dCQUNuQixhQUFhLEVBQUUsVUFBVTthQUMxQjtTQUNGLENBQUMsQ0FBQztRQUVILGNBQWMsQ0FBQyxLQUFLLENBQUMsZUFBZSxFQUFFO1lBQ3BDLEdBQUcsRUFBRSxVQUFVO1lBQ2YsTUFBTSxFQUFFLENBQUM7WUFDVCxLQUFLLEVBQUU7Z0JBQ0wsU0FBUyxFQUFFO29CQUNULFdBQVcsRUFBRSxvQ0FBb0M7b0JBQ2pELFVBQVUsRUFBRSxjQUFjO2lCQUMzQjthQUNGO1NBQ0YsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7O0FBRUgsb0JBQW9CO0FBQ3BCLHFCQUFxQjtBQUNyQiwyQkFBMkIiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBpbXBvcnQgKiBhcyBhbmd1bGFyIGZyb20gJ2FuZ3VsYXJBTUQnO1xuZGVjbGFyZSB2YXIgYW5ndWxhcjogYW5ndWxhci5JQW5ndWxhclN0YXRpYzsgXG5cbmV4cG9ydCBjb25zdCBzZWN1cml0eSA9IGFuZ3VsYXIubW9kdWxlKCdhcHAuc2VjdXJpdHknLCBbJ2FwcC5jb3JlJ10pO1xuXG5zZWN1cml0eS5jb25maWcoZnVuY3Rpb24gKCRzdGF0ZVByb3ZpZGVyLCAkY29tcGlsZVByb3ZpZGVyLCAkY29udHJvbGxlclByb3ZpZGVyLCAkcHJvdmlkZSwgTmF2SGVscGVyUHJvdmlkZXIsICRodHRwUHJvdmlkZXIsICR0cmFuc2xhdGVQcm92aWRlciwgJHRyYW5zbGF0ZVBhcnRpYWxMb2FkZXJQcm92aWRlcikge1xuXG4gIC8vJHRyYW5zbGF0ZVBhcnRpYWxMb2FkZXJQcm92aWRlci5hZGRQYXJ0KCdhcHAvc2VjdXJpdHkvbG9jYWxlL2xvY2FsZScpO1xuXG4gIE5hdkhlbHBlclByb3ZpZGVyLmFkZENvbnRyb2xsZXJVcmwoJ2FwcC9zZWN1cml0eS9zZWN1cml0eS5jb250cm9sbGVyJyk7XG4gIE5hdkhlbHBlclByb3ZpZGVyLmFkZFRvTWVudSgnc2VjdXJpdHknLCB7XG4gICAgXCJsaW5rXCI6IFwiIy9zZWN1cml0eVwiLFxuICAgIFwiYWN0aXZlXCI6IFwibWFpbi5zZWN1cml0eVwiLFxuICAgIFwidGl0bGVcIjogXCJTZWN1cml0eVwiLFxuICAgIFwiaWNvblwiOiBcImZhICBmYS1zaGllbGRcIiwgIC8vIEFkZCBuYXZpZ2F0aW9uIGljb24gY3NzIGNsYXNzIGhlcmVcbiAgICBcInBhZ2VcIjoge1xuICAgICAgXCJ0aXRsZVwiOiBcIlNlY3VyaXR5XCIsXG4gICAgICBcImRlc2NyaXB0aW9uXCI6IFwic2VjdXJpdHlcIlxuICAgIH1cbiAgfSk7XG5cbiAgJHN0YXRlUHJvdmlkZXIuc3RhdGUoJ21haW4uc2VjdXJpdHknLCB7XG4gICAgdXJsOiAnc2VjdXJpdHknLFxuICAgIGFjY2VzczogMixcbiAgICB2aWV3czoge1xuICAgICAgJ2NvbnRlbnQnOiB7XG4gICAgICAgIHRlbXBsYXRlVXJsOiAnc3JjL2FwcC9zZWN1cml0eS9zZWN1cml0eS50cGwuaHRtbCcsXG4gICAgICAgIGNvbnRyb2xsZXI6ICdzZWN1cml0eUN0cmwnXG4gICAgICB9XG4gICAgfVxuICB9KTtcbn0pO1xuXG4vKiBub24gRVM2IGV4cG9ydCAqL1xuLy8gZXhwb3J0ID0gc2VjdXJpdHk7XG4vLyBleHBvcnQgZGVmYXVsdCBzZWN1cml0eTsiXX0=
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.ts b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.ts new file mode 100644 index 00000000..e06ae9ac --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.ts @@ -0,0 +1,36 @@ +// import * as angular from 'angularAMD'; +declare var angular: angular.IAngularStatic; + +export const security = angular.module('app.security', ['app.core']); + +security.config(function ($stateProvider, $compileProvider, $controllerProvider, $provide, NavHelperProvider, $httpProvider, $translateProvider, $translatePartialLoaderProvider) { + + //$translatePartialLoaderProvider.addPart('app/security/locale/locale'); + + NavHelperProvider.addControllerUrl('app/security/security.controller'); + NavHelperProvider.addToMenu('security', { + "link": "#/security", + "active": "main.security", + "title": "Security", + "icon": "fa fa-shield", // Add navigation icon css class here + "page": { + "title": "Security", + "description": "security" + } + }); + + $stateProvider.state('main.security', { + url: 'security', + access: 2, + views: { + 'content': { + templateUrl: 'src/app/security/security.tpl.html', + controller: 'securityCtrl' + } + } + }); +}); + +/* non ES6 export */ +// export = security; +// export default security;
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.service.ts b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.service.ts new file mode 100644 index 00000000..c881c53f --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.service.ts @@ -0,0 +1,99 @@ +import * as angular from 'angularAMD'; + +const security = angular.module('app.security'); + +interface IEnvService { + getBaseURL(port: string): string; +} + +export type User = { + description: string; + domainid: string; + email: string; + enabled: boolean; + password: string; + salt: string; + userid: string; +} + +export type Role = { + roleid: string; + name: string; + description: string; + domainid: string; +} + +export class SecurityService { + private credentials: ng.IPromise<string>; + + constructor(private $q: ng.IQService, private $http: ng.IHttpService, private $window, private env: IEnvService) { + this.ensureCrendentials(); + } + + private ensureCrendentials() { + const credentialsDefer = this.$q.defer<string>(); + this.credentials = credentialsDefer.promise; + + const url = `${this.env.getBaseURL('MD_SAL')}/oauth2/token`; + this.$http<{ access_token: string }>({ + method: "POST", + url: url, + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + data: `grant_type=password&username=${this.$window.sessionStorage.odlUser}&password=${this.$window.sessionStorage.odlPass}&scope=sdn` + }).then(res => { + credentialsDefer.resolve(res.data && res.data.access_token); + }, err => { + credentialsDefer.reject(err); + }); + } + + public get token() { + return this.credentials; + } + + public getAllUsers(): ng.IPromise<User[]> { + const url = `${this.env.getBaseURL('MD_SAL')}/auth/v1/users`; + return this.token.then(token => { + return this.$http<{ users: User[] }>({ + method: "GET", + url: url, + headers: { 'Authorization': `Bearer ${token}` } + }).then(result => result.data && result.data.users) + }); + } + + public getAllRoles(): ng.IPromise<Role[]> { + const url = `${this.env.getBaseURL('MD_SAL')}/auth/v1/roles`; + return this.token.then(token => { + return this.$http<{ roles: Role[] }>({ + method: "GET", + url: url, + headers: { 'Authorization': `Bearer ${token}` } + }).then(result => result.data && result.data.roles) + }); + } + + public getUserById(userId: string): ng.IPromise<User> { + const url = `${this.env.getBaseURL('MD_SAL')}/auth/v1/users/${userId}`; + return this.token.then(token => { + return this.$http<User>({ + method: "GET", + url: url, + headers: { 'Authorization': `Bearer ${token}` } + }).then(result => result.data && result.data) + }); + } + + public getRolesForDomainUser(userId: string, domain: string= "sdn"): ng.IPromise<Role[]> { + const url = `${this.env.getBaseURL('MD_SAL')}/auth/v1/domains/${domain}/users/${userId}/roles`; + return this.token.then(token => { + return this.$http<{ roles: Role[] }>({ + method: "GET", + url: url, + headers: { 'Authorization': `Bearer ${token}` } + }).then(result => result.data && result.data.roles) + }); + } +} + +security.service('securityService', ['$q', '$http', '$window', 'ENV', SecurityService]);
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.tpl.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.tpl.html new file mode 100644 index 00000000..ea08892b --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.tpl.html @@ -0,0 +1,50 @@ +<div id="security"> + <h2>Users</h2> + <table class="table"> + <thead> + <tr> + <th>UserID</th> + <th>Name</th> + <th>Description</th> + <th>Enabled</th> + <th>eMail</th> + <th>Domain</th> + <th>Actions</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="user in users"> + <td>{{user.userid}}</td> + <td>{{user.name}}</td> + <td>{{user.description}}</td> + <td>{{user.enabled}}</td> + <td>{{user.email}}</td> + <td>{{user.domainid}}</td> + <td> + <button class="btn btn-sm btn-success" + ng-click="getCurrentUserById(user.userid)">Info</button></td> + </tr> + </tbody> + </table> +<h2>Roles</h2> +<table class="table"> + <thead> + <tr> + <th>RoleID</th> + <th>Name</th> + <th>Description</th> + <th>Domain</th> + <!-- <th>Actions</th> --> + </tr> + </thead> + <tbody> + <tr ng-repeat="role in roles"> + <td>{{role.roleid}}</td> + <td>{{role.name}}</td> + <td>{{role.description}}</td> + <td>{{role.domainid}}</td> + <!-- <td><button class="btn btn-sm btn-success">Info</button></td> --> + </tr> + </tbody> +</table> +</div>
\ No newline at end of file diff --git a/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/templates/userDetails.html b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/templates/userDetails.html new file mode 100644 index 00000000..5589263b --- /dev/null +++ b/sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/templates/userDetails.html @@ -0,0 +1,14 @@ +<div class="modal-header"> + <h3 class="modal-title" id="modal-title" style="color: #333;">{{ vm.userid }}</h3> +</div> +<div class="modal-body" id="modal-body"> + <div><b>Roles</b></div> + <ul> + <li ng-repeat="role in vm.roles">{{ role.name }}</li> + </ul> + +</div> +<div class="modal-footer"> + <button class="btn btn-primary" type="button" ng-click="vm.ok()">OK</button> + <button class="btn btn-warning" type="button" ng-click="vm.cancel()">Cancel</button> +</div>
\ No newline at end of file |