summaryrefslogtreecommitdiffstats
path: root/sdnr/wireless-transport/code-Carbon-SR1/ux/security
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wireless-transport/code-Carbon-SR1/ux/security')
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/pom.xml28
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/pom.xml80
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-bundle/src/main/resources/OSGI-INF/blueprint/blueprint.xml19
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/pom.xml18
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/build.config.js42
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/gulpfile.js142
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/package.json29
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.js149
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.controller.ts63
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.custom.css11
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.js33
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.module.ts36
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.service.ts99
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/security.tpl.html50
-rw-r--r--sdnr/wireless-transport/code-Carbon-SR1/ux/security/security-module/src/main/resources/security/src/templates/userDetails.html14
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