KEYCLOAK-1866
Allow changing name and view details of imported realm
This commit is contained in:
parent
d08fca4e0a
commit
7ac1d1f14c
6 changed files with 70 additions and 116 deletions
|
@ -2036,3 +2036,26 @@ module.directive( 'kcOpen', function ( $location ) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.directive('kcOnReadFile', function ($parse) {
|
||||||
|
console.debug('kcOnReadFile');
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
scope: false,
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
var fn = $parse(attrs.kcOnReadFile);
|
||||||
|
|
||||||
|
element.on('change', function(onChangeEvent) {
|
||||||
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onload = function(onLoadEvent) {
|
||||||
|
scope.$apply(function() {
|
||||||
|
fn(scope, {$fileContent:onLoadEvent.target.result});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsText((onChangeEvent.srcElement || onChangeEvent.target).files[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
|
@ -155,7 +155,7 @@ module.controller('RealmDropdownCtrl', function($scope, Realm, Current, Auth, $l
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, Dialog, Notifications, Auth) {
|
module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $http, WhoAmI, $location, $route, Dialog, Notifications, Auth, $modal) {
|
||||||
console.log('RealmCreateCtrl');
|
console.log('RealmCreateCtrl');
|
||||||
|
|
||||||
Current.realm = null;
|
Current.realm = null;
|
||||||
|
@ -169,55 +169,21 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||||
|
|
||||||
var oldCopy = angular.copy($scope.realm);
|
var oldCopy = angular.copy($scope.realm);
|
||||||
|
|
||||||
$scope.onFileSelect = function($files) {
|
$scope.importFile = function($fileContent){
|
||||||
$scope.files = $files;
|
$scope.realm = angular.copy(JSON.parse($fileContent));
|
||||||
|
$scope.importing = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.clearFileSelect = function() {
|
$scope.viewImportDetails = function() {
|
||||||
$scope.files = null;
|
$modal.open({
|
||||||
}
|
templateUrl: resourceUrl + '/partials/modal/view-object.html',
|
||||||
|
controller: 'ObjectModalCtrl',
|
||||||
$scope.uploadFile = function() {
|
resolve: {
|
||||||
//$files: an array of files selected, each file has name, size, and type.
|
object: function () {
|
||||||
for (var i = 0; i < $scope.files.length; i++) {
|
return $scope.realm;
|
||||||
var $file = $scope.files[i];
|
}
|
||||||
$scope.upload = $upload.upload({
|
}
|
||||||
url: authUrl + '/admin/realms', //upload.php script, node.js route, or servlet url
|
})
|
||||||
// method: POST or PUT,
|
|
||||||
// headers: {'headerKey': 'headerValue'}, withCredential: true,
|
|
||||||
data: {myObj: ""},
|
|
||||||
file: $file
|
|
||||||
/* set file formData name for 'Content-Desposition' header. Default: 'file' */
|
|
||||||
//fileFormDataName: myFile,
|
|
||||||
/* customize how data is added to formData. See #40#issuecomment-28612000 for example */
|
|
||||||
//formDataAppender: function(formData, key, val){}
|
|
||||||
}).progress(function(evt) {
|
|
||||||
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
|
||||||
}).success(function(data, status, headers) {
|
|
||||||
Realm.query(function(data) {
|
|
||||||
Current.realms = data;
|
|
||||||
|
|
||||||
|
|
||||||
WhoAmI.get(function(user) {
|
|
||||||
Auth.user = user;
|
|
||||||
|
|
||||||
Notifications.success("The realm has been uploaded.");
|
|
||||||
|
|
||||||
var location = headers('Location');
|
|
||||||
if (location) {
|
|
||||||
$location.url("/realms/" + location.substring(location.lastIndexOf('/') + 1));
|
|
||||||
} else {
|
|
||||||
$location.url("/realms");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.error(function() {
|
|
||||||
Notifications.error("The realm can not be uploaded. Please verify the file.");
|
|
||||||
|
|
||||||
});
|
|
||||||
//.then(success, error, progress);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.$watch('realm', function() {
|
$scope.$watch('realm', function() {
|
||||||
|
@ -226,6 +192,12 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
$scope.$watch('realm.realm', function() {
|
||||||
|
if (create) {
|
||||||
|
$scope.realm.id = $scope.realm.realm;
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
|
||||||
$scope.save = function() {
|
$scope.save = function() {
|
||||||
var realmCopy = angular.copy($scope.realm);
|
var realmCopy = angular.copy($scope.realm);
|
||||||
Realm.create(realmCopy, function() {
|
Realm.create(realmCopy, function() {
|
||||||
|
@ -243,10 +215,17 @@ module.controller('RealmCreateCtrl', function($scope, Current, Realm, $upload, $
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.cancel = function() {
|
$scope.cancel = function() {
|
||||||
window.history.back();
|
$location.url("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.reset = function() {
|
||||||
|
$route.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.controller('ObjectModalCtrl', function($scope, object) {
|
||||||
|
$scope.object = object;
|
||||||
|
});
|
||||||
|
|
||||||
module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications, WhoAmI, Auth) {
|
module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, serverInfo, $http, $location, Dialog, Notifications, WhoAmI, Auth) {
|
||||||
$scope.createRealm = !realm.realm;
|
$scope.createRealm = !realm.realm;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div style="padding: 20px 20px 10px 20px">
|
||||||
|
<pre ng-bind = "{{object}} | json"></pre>
|
||||||
|
</div>
|
|
@ -1,29 +1,22 @@
|
||||||
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
|
||||||
<form class="form-horizontal" name="realmForm" novalidate>
|
|
||||||
<fieldset>
|
|
||||||
<legend><span class="text">Import Realm</span></legend>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="import-file" class="col-sm-2 control-label">Import JSON File </label>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="controls kc-button-input-file" data-ng-show="!files || files.length == 0">
|
|
||||||
<label for="import-file" class="btn btn-default">Select file <i class="pficon pficon-import"></i></label>
|
|
||||||
<input id="import-file" type="file" class="hidden" ng-file-select="onFileSelect($files)">
|
|
||||||
</div>
|
|
||||||
<span class="kc-uploaded-file" data-ng-show="files.length > 0">{{files[0].name}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-10 col-md-offset-2">
|
|
||||||
<button type="submit" data-ng-disabled="files.length == 0" data-ng-click="uploadFile()" class="btn btn-primary">Upload</button>
|
|
||||||
<button type="submit" data-ng-disabled="files.length == 0" data-ng-click="clearFileSelect()" class="btn btn-default">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<form class="form-horizontal" name="realmForm" novalidate>
|
<form class="form-horizontal" name="realmForm" novalidate>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend><span class="text">Create Realm</span></legend>
|
<legend><span class="text">Create Realm</span></legend>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name" class="col-sm-2 control-label">Import</label>
|
||||||
|
|
||||||
|
<div class="col-md-6" data-ng-hide="importing">
|
||||||
|
<label for="import-file" class="btn btn-default">Select file <i class="pficon pficon-import"></i></label>
|
||||||
|
<input id="import-file" type="file" class="hidden" kc-on-read-file="importFile($fileContent)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6" data-ng-show="importing">
|
||||||
|
<button class="btn btn-default" data-ng-click="viewImportDetails()">View details</button>
|
||||||
|
<button class="btn btn-default" data-ng-click="reset()">Clear import</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="name" class="col-sm-2 control-label">Name <span class="required">*</span></label>
|
<label for="name" class="col-sm-2 control-label">Name <span class="required">*</span></label>
|
||||||
|
|
||||||
|
@ -42,6 +35,7 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-10 col-md-offset-2">
|
<div class="col-md-10 col-md-offset-2">
|
||||||
<button kc-save data-ng-disabled="!changed">Create</button>
|
<button kc-save data-ng-disabled="!changed">Create</button>
|
||||||
|
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -111,7 +111,7 @@ public class RealmAdminResource {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Path("attack-detection")
|
@Path("attack-detection")
|
||||||
public AttackDetectionResource getClientImporter() {
|
public AttackDetectionResource getAttackDetection() {
|
||||||
AttackDetectionResource resource = new AttackDetectionResource(auth, realm, adminEvent);
|
AttackDetectionResource resource = new AttackDetectionResource(auth, realm, adminEvent);
|
||||||
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
ResteasyProviderFactory.getInstance().injectProperties(resource);
|
||||||
return resource;
|
return resource;
|
||||||
|
|
|
@ -144,51 +144,6 @@ public class RealmsAdminResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a realm from uploaded JSON file
|
|
||||||
*
|
|
||||||
* The posted represenation is expected to be a multipart/form-data encapsulation
|
|
||||||
* of a JSON file. The same format a browser would use when uploading a file.
|
|
||||||
*
|
|
||||||
* @param uriInfo
|
|
||||||
* @param input multipart/form data
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@POST
|
|
||||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
|
||||||
public Response uploadRealm(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
|
||||||
RealmManager realmManager = new RealmManager(session);
|
|
||||||
realmManager.setContextPath(keycloak.getContextPath());
|
|
||||||
if (!auth.getRealm().equals(realmManager.getKeycloakAdminstrationRealm())) {
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
if (!auth.hasRealmRole(AdminRoles.CREATE_REALM)) {
|
|
||||||
throw new ForbiddenException();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
|
||||||
List<InputPart> inputParts = uploadForm.get("file");
|
|
||||||
RealmRepresentation rep = null;
|
|
||||||
|
|
||||||
for (InputPart inputPart : inputParts) {
|
|
||||||
// inputPart.getBody doesn't work as content-type is wrong, and inputPart.setMediaType is not supported on AS7 (RestEasy 2.3.2.Final)
|
|
||||||
rep = JsonSerialization.readValue(inputPart.getBodyAsString(), RealmRepresentation.class);
|
|
||||||
|
|
||||||
RealmModel realm = realmManager.importRealm(rep);
|
|
||||||
|
|
||||||
grantPermissionsToRealmCreator(realm);
|
|
||||||
|
|
||||||
URI location = null;
|
|
||||||
if (inputParts.size() == 1) {
|
|
||||||
location = AdminRoot.realmsUrl(uriInfo).path(realm.getName()).build();
|
|
||||||
return Response.created(location).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response.noContent().build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void grantPermissionsToRealmCreator(RealmModel realm) {
|
private void grantPermissionsToRealmCreator(RealmModel realm) {
|
||||||
if (auth.hasRealmRole(AdminRoles.ADMIN)) {
|
if (auth.hasRealmRole(AdminRoles.ADMIN)) {
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in a new issue