Merge pull request #803 from patriot1burke/master
saml entity descriptor importer
This commit is contained in:
commit
802e184ca9
42 changed files with 1914 additions and 173 deletions
|
@ -476,8 +476,8 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
controller : 'ApplicationClusteringNodeCtrl'
|
controller : 'ApplicationClusteringNodeCtrl'
|
||||||
})
|
})
|
||||||
.when('/realms/:realm/applications/:application/certificate', {
|
.when('/realms/:realm/applications/:application/saml/keys', {
|
||||||
templateUrl : 'partials/application-keys.html',
|
templateUrl : 'partials/application-saml-keys.html',
|
||||||
resolve : {
|
resolve : {
|
||||||
realm : function(RealmLoader) {
|
realm : function(RealmLoader) {
|
||||||
return RealmLoader();
|
return RealmLoader();
|
||||||
|
@ -486,7 +486,31 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
return ApplicationLoader();
|
return ApplicationLoader();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
controller : 'ApplicationCertificateCtrl'
|
controller : 'ApplicationSamlKeyCtrl'
|
||||||
|
})
|
||||||
|
.when('/realms/:realm/applications/:application/saml/:keyType/import/:attribute', {
|
||||||
|
templateUrl : 'partials/application-saml-key-import.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
application : function(ApplicationLoader) {
|
||||||
|
return ApplicationLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'ApplicationCertificateImportCtrl'
|
||||||
|
})
|
||||||
|
.when('/realms/:realm/applications/:application/saml/:keyType/export/:attribute', {
|
||||||
|
templateUrl : 'partials/application-saml-key-export.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
application : function(ApplicationLoader) {
|
||||||
|
return ApplicationLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'ApplicationCertificateExportCtrl'
|
||||||
})
|
})
|
||||||
.when('/realms/:realm/applications/:application/roles', {
|
.when('/realms/:realm/applications/:application/roles', {
|
||||||
templateUrl : 'partials/application-role-list.html',
|
templateUrl : 'partials/application-role-list.html',
|
||||||
|
@ -553,6 +577,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
application : function() {
|
application : function() {
|
||||||
return {};
|
return {};
|
||||||
|
},
|
||||||
|
serverInfo : function(ServerInfoLoader) {
|
||||||
|
return ServerInfoLoader();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
controller : 'ApplicationDetailCtrl'
|
controller : 'ApplicationDetailCtrl'
|
||||||
|
@ -568,6 +595,9 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
application : function(ApplicationLoader) {
|
application : function(ApplicationLoader) {
|
||||||
return ApplicationLoader();
|
return ApplicationLoader();
|
||||||
|
},
|
||||||
|
serverInfo : function(ServerInfoLoader) {
|
||||||
|
return ServerInfoLoader();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
controller : 'ApplicationDetailCtrl'
|
controller : 'ApplicationDetailCtrl'
|
||||||
|
@ -580,10 +610,26 @@ module.config([ '$routeProvider', function($routeProvider) {
|
||||||
},
|
},
|
||||||
applications : function(ApplicationListLoader) {
|
applications : function(ApplicationListLoader) {
|
||||||
return ApplicationListLoader();
|
return ApplicationListLoader();
|
||||||
|
},
|
||||||
|
serverInfo : function(ServerInfoLoader) {
|
||||||
|
return ServerInfoLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
controller : 'ApplicationListCtrl'
|
controller : 'ApplicationListCtrl'
|
||||||
})
|
})
|
||||||
|
.when('/import/application/:realm', {
|
||||||
|
templateUrl : 'partials/application-import.html',
|
||||||
|
resolve : {
|
||||||
|
realm : function(RealmLoader) {
|
||||||
|
return RealmLoader();
|
||||||
|
},
|
||||||
|
serverInfo : function(ServerInfoLoader) {
|
||||||
|
return ServerInfoLoader();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
controller : 'ApplicationImportCtrl'
|
||||||
|
})
|
||||||
|
|
||||||
// OAUTH Client
|
// OAUTH Client
|
||||||
|
|
||||||
|
|
|
@ -43,16 +43,82 @@ module.controller('ApplicationCredentialsCtrl', function($scope, $location, real
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('ApplicationCertificateCtrl', function($scope, $location, $http, $upload, realm, application,
|
module.controller('ApplicationSamlKeyCtrl', function($scope, $location, $http, $upload, realm, application,
|
||||||
ApplicationCertificate, ApplicationCertificateGenerate,
|
ApplicationCertificate, ApplicationCertificateGenerate,
|
||||||
ApplicationCertificateDownload, Notifications) {
|
ApplicationCertificateDownload, Notifications) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
$scope.application = application;
|
$scope.application = application;
|
||||||
var jks = {
|
|
||||||
keyAlias: application.name,
|
var signingKeyInfo = ApplicationCertificate.get({ realm : realm.realm, application : application.id, attribute: 'saml.signing' },
|
||||||
realmAlias: realm.realm
|
function() {
|
||||||
|
$scope.signingKeyInfo = signingKeyInfo;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$scope.generateSigningKey = function() {
|
||||||
|
var keyInfo = ApplicationCertificateGenerate.generate({ realm : realm.realm, application : application.id, attribute: 'saml.signing' },
|
||||||
|
function() {
|
||||||
|
Notifications.success('Signing key has been regenerated.');
|
||||||
|
$scope.signingKeyInfo = keyInfo;
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
Notifications.error("Signing key was not regenerated.");
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.importSigningKey = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/saml/Signing/import/saml.signing");
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.exportSigningKey = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/saml/Signing/export/saml.signing");
|
||||||
|
};
|
||||||
|
|
||||||
|
var encryptionKeyInfo = ApplicationCertificate.get({ realm : realm.realm, application : application.id, attribute: 'saml.encryption' },
|
||||||
|
function() {
|
||||||
|
$scope.encryptionKeyInfo = encryptionKeyInfo;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$scope.generateEncryptionKey = function() {
|
||||||
|
var keyInfo = ApplicationCertificateGenerate.generate({ realm : realm.realm, application : application.id, attribute: 'saml.encryption' },
|
||||||
|
function() {
|
||||||
|
Notifications.success('Encryption key has been regenerated.');
|
||||||
|
$scope.encryptionKeyInfo = keyInfo;
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
Notifications.error("Encryption key was not regenerated.");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.importEncryptionKey = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/saml/Encryption/import/saml.encryption");
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.exportEncryptionKey = function() {
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/saml/Encryption/export/saml.encryption");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$scope.$watch(function() {
|
||||||
|
return $location.path();
|
||||||
|
}, function() {
|
||||||
|
$scope.path = $location.path().substring(1).split("/");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('ApplicationCertificateImportCtrl', function($scope, $location, $http, $upload, realm, application, $routeParams,
|
||||||
|
ApplicationCertificate, ApplicationCertificateGenerate,
|
||||||
|
ApplicationCertificateDownload, Notifications) {
|
||||||
|
|
||||||
|
var keyType = $routeParams.keyType;
|
||||||
|
var attribute = $routeParams.attribute;
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.application = application;
|
||||||
|
$scope.keyType = keyType;
|
||||||
|
|
||||||
$scope.files = [];
|
$scope.files = [];
|
||||||
|
|
||||||
$scope.onFileSelect = function($files) {
|
$scope.onFileSelect = function($files) {
|
||||||
|
@ -68,8 +134,6 @@ module.controller('ApplicationCertificateCtrl', function($scope, $location, $htt
|
||||||
"PKCS12"
|
"PKCS12"
|
||||||
];
|
];
|
||||||
|
|
||||||
$scope.jks = jks;
|
|
||||||
$scope.jks.format = $scope.keyFormats[0];
|
|
||||||
$scope.uploadKeyFormat = $scope.keyFormats[0];
|
$scope.uploadKeyFormat = $scope.keyFormats[0];
|
||||||
|
|
||||||
$scope.uploadFile = function() {
|
$scope.uploadFile = function() {
|
||||||
|
@ -77,7 +141,7 @@ module.controller('ApplicationCertificateCtrl', function($scope, $location, $htt
|
||||||
for (var i = 0; i < $scope.files.length; i++) {
|
for (var i = 0; i < $scope.files.length; i++) {
|
||||||
var $file = $scope.files[i];
|
var $file = $scope.files[i];
|
||||||
$scope.upload = $upload.upload({
|
$scope.upload = $upload.upload({
|
||||||
url: authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/certificates/upload/jks',
|
url: authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/certificates/' + attribute + '/upload',
|
||||||
// method: POST or PUT,
|
// method: POST or PUT,
|
||||||
// headers: {'headerKey': 'headerValue'}, withCredential: true,
|
// headers: {'headerKey': 'headerValue'}, withCredential: true,
|
||||||
data: {keystoreFormat: $scope.uploadKeyFormat,
|
data: {keystoreFormat: $scope.uploadKeyFormat,
|
||||||
|
@ -93,8 +157,8 @@ module.controller('ApplicationCertificateCtrl', function($scope, $location, $htt
|
||||||
}).progress(function(evt) {
|
}).progress(function(evt) {
|
||||||
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
|
||||||
}).success(function(data, status, headers) {
|
}).success(function(data, status, headers) {
|
||||||
$scope.keyInfo = data;
|
|
||||||
Notifications.success("Keystore uploaded successfully.");
|
Notifications.success("Keystore uploaded successfully.");
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications/" + application.id + "/saml/keys");
|
||||||
})
|
})
|
||||||
.error(function() {
|
.error(function() {
|
||||||
Notifications.error("The key store can not be uploaded. Please verify the file.");
|
Notifications.error("The key store can not be uploaded. Please verify the file.");
|
||||||
|
@ -104,30 +168,42 @@ module.controller('ApplicationCertificateCtrl', function($scope, $location, $htt
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.$watch(function() {
|
||||||
|
return $location.path();
|
||||||
|
}, function() {
|
||||||
|
$scope.path = $location.path().substring(1).split("/");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.controller('ApplicationCertificateExportCtrl', function($scope, $location, $http, $upload, realm, application, $routeParams,
|
||||||
|
ApplicationCertificate, ApplicationCertificateGenerate,
|
||||||
var keyInfo = ApplicationCertificate.get({ realm : realm.realm, application : application.id },
|
ApplicationCertificateDownload, Notifications) {
|
||||||
function() {
|
var keyType = $routeParams.keyType;
|
||||||
$scope.keyInfo = keyInfo;
|
var attribute = $routeParams.attribute;
|
||||||
}
|
$scope.realm = realm;
|
||||||
);
|
$scope.application = application;
|
||||||
|
$scope.keyType = keyType;
|
||||||
$scope.generate = function() {
|
var jks = {
|
||||||
var keyInfo = ApplicationCertificateGenerate.generate({ realm : realm.realm, application : application.id },
|
keyAlias: application.name,
|
||||||
function() {
|
realmAlias: realm.realm
|
||||||
Notifications.success('Client keypair and cert has been changed.');
|
|
||||||
$scope.keyInfo = keyInfo;
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
Notifications.error("Client keypair and cert was not changed due to a problem.");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.downloadJKS = function() {
|
$scope.keyFormats = [
|
||||||
|
"JKS",
|
||||||
|
"PKCS12"
|
||||||
|
];
|
||||||
|
|
||||||
|
var keyInfo = ApplicationCertificate.get({ realm : realm.realm, application : application.id, attribute: attribute },
|
||||||
|
function() {
|
||||||
|
$scope.keyInfo = keyInfo;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$scope.jks = jks;
|
||||||
|
$scope.jks.format = $scope.keyFormats[0];
|
||||||
|
|
||||||
|
$scope.download = function() {
|
||||||
$http({
|
$http({
|
||||||
url: authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/certificates/download',
|
url: authUrl + '/admin/realms/' + realm.realm + '/applications-by-id/' + application.id + '/certificates/' + attribute + '/download',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
responseType: 'arraybuffer',
|
responseType: 'arraybuffer',
|
||||||
data: $scope.jks,
|
data: $scope.jks,
|
||||||
|
@ -290,9 +366,62 @@ module.controller('ApplicationRoleDetailCtrl', function($scope, realm, applicati
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('ApplicationListCtrl', function($scope, realm, applications, Application, $location) {
|
module.controller('ApplicationImportCtrl', function($scope, $location, $upload, realm, serverInfo, Notifications) {
|
||||||
|
|
||||||
|
$scope.realm = realm;
|
||||||
|
$scope.configFormats = serverInfo.applicationImporters;
|
||||||
|
$scope.configFormat = null;
|
||||||
|
|
||||||
|
$scope.files = [];
|
||||||
|
|
||||||
|
$scope.onFileSelect = function($files) {
|
||||||
|
$scope.files = $files;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.clearFileSelect = function() {
|
||||||
|
$scope.files = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.uploadFile = function() {
|
||||||
|
//$files: an array of files selected, each file has name, size, and type.
|
||||||
|
for (var i = 0; i < $scope.files.length; i++) {
|
||||||
|
var $file = $scope.files[i];
|
||||||
|
$scope.upload = $upload.upload({
|
||||||
|
url: authUrl + '/admin/realms/' + realm.realm + '/application-importers/' + $scope.configFormat.id + '/upload',
|
||||||
|
// 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) {
|
||||||
|
Notifications.success("Uploaded successfully.");
|
||||||
|
$location.url("/realms/" + realm.realm + "/applications");
|
||||||
|
})
|
||||||
|
.error(function() {
|
||||||
|
Notifications.error("The file can not be uploaded. Please verify the file.");
|
||||||
|
|
||||||
|
});
|
||||||
|
//.then(success, error, progress);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch(function() {
|
||||||
|
return $location.path();
|
||||||
|
}, function() {
|
||||||
|
$scope.path = $location.path().substring(1).split("/");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
module.controller('ApplicationListCtrl', function($scope, realm, applications, Application, serverInfo, $location) {
|
||||||
$scope.realm = realm;
|
$scope.realm = realm;
|
||||||
$scope.applications = applications;
|
$scope.applications = applications;
|
||||||
|
$scope.importButton = serverInfo.applicationImporters.length > 0;
|
||||||
$scope.$watch(function() {
|
$scope.$watch(function() {
|
||||||
return $location.path();
|
return $location.path();
|
||||||
}, function() {
|
}, function() {
|
||||||
|
@ -335,7 +464,7 @@ module.controller('ApplicationInstallationCtrl', function($scope, realm, applica
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('ApplicationDetailCtrl', function($scope, realm, application, Application, $location, Dialog, Notifications) {
|
module.controller('ApplicationDetailCtrl', function($scope, realm, application, serverInfo, Application, $location, Dialog, Notifications) {
|
||||||
console.log('ApplicationDetailCtrl');
|
console.log('ApplicationDetailCtrl');
|
||||||
|
|
||||||
$scope.accessTypes = [
|
$scope.accessTypes = [
|
||||||
|
@ -344,10 +473,8 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
|
||||||
"bearer-only"
|
"bearer-only"
|
||||||
];
|
];
|
||||||
|
|
||||||
$scope.protocols = [
|
$scope.protocols = serverInfo.protocols;
|
||||||
"openid-connect",
|
|
||||||
"saml"
|
|
||||||
];
|
|
||||||
$scope.signatureAlgorithms = [
|
$scope.signatureAlgorithms = [
|
||||||
"RSA_SHA1",
|
"RSA_SHA1",
|
||||||
"RSA_SHA256",
|
"RSA_SHA256",
|
||||||
|
@ -375,11 +502,9 @@ module.controller('ApplicationDetailCtrl', function($scope, realm, application,
|
||||||
} else if (application.publicClient) {
|
} else if (application.publicClient) {
|
||||||
$scope.accessType = $scope.accessTypes[1];
|
$scope.accessType = $scope.accessTypes[1];
|
||||||
}
|
}
|
||||||
if (application.protocol == 'openid-connect') {
|
if (application.protocol) {
|
||||||
$scope.protocol = $scope.protocols[0];
|
$scope.protocol = $scope.protocols[$scope.protocols.indexOf(application.protocol)];
|
||||||
} else if (application.protocol == 'saml') {
|
} else {
|
||||||
$scope.protocol = $scope.protocols[1];
|
|
||||||
} else { // protocol could be null due to older keycloak installs
|
|
||||||
$scope.protocol = $scope.protocols[0];
|
$scope.protocol = $scope.protocols[0];
|
||||||
}
|
}
|
||||||
if (application.attributes['saml.signature.algorithm'] == 'RSA_SHA1') {
|
if (application.attributes['saml.signature.algorithm'] == 'RSA_SHA1') {
|
||||||
|
|
|
@ -708,16 +708,18 @@ module.factory('ApplicationTestNodesAvailable', function($resource) {
|
||||||
});
|
});
|
||||||
|
|
||||||
module.factory('ApplicationCertificate', function($resource) {
|
module.factory('ApplicationCertificate', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates', {
|
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates/:attribute', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
application : "@application"
|
application : "@application",
|
||||||
|
attribute: "@attribute"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.factory('ApplicationCertificateGenerate', function($resource) {
|
module.factory('ApplicationCertificateGenerate', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates/generate', {
|
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates/:attribute/generate', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
application : "@application"
|
application : "@application",
|
||||||
|
attribute: "@attribute"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
generate : {
|
generate : {
|
||||||
|
@ -727,9 +729,10 @@ module.factory('ApplicationCertificateGenerate', function($resource) {
|
||||||
});
|
});
|
||||||
|
|
||||||
module.factory('ApplicationCertificateDownload', function($resource) {
|
module.factory('ApplicationCertificateDownload', function($resource) {
|
||||||
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates/download', {
|
return $resource(authUrl + '/admin/realms/:realm/applications-by-id/:application/certificates/:attribute/download', {
|
||||||
realm : '@realm',
|
realm : '@realm',
|
||||||
application : "@application"
|
application : "@application",
|
||||||
|
attribute: "@attribute"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
download : {
|
download : {
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||||
|
<div id="content-area" class="col-md-9" role="main">
|
||||||
|
<ul class="nav nav-tabs nav-tabs-pf">
|
||||||
|
<li class="active"><a href="">Application Import</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2></h2>
|
||||||
|
<div id="content">
|
||||||
|
<h2><span>{{application.name}}</span> Application Import <span tooltip-placement="right" tooltip="Helper utility for importing application definitions from various formats." class="fa fa-info-circle"></span></h2>
|
||||||
|
<form class="form-horizontal" name="realmForm" novalidate>
|
||||||
|
<fieldset class="border-top">
|
||||||
|
<div class="form-group input-select">
|
||||||
|
<label class="col-sm-2 control-label" for="configFormats">Format Option</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="select-kc">
|
||||||
|
<select id="configFormats" name="configFormats" ng-model="configFormat" ng-options="format.name for format in configFormats">
|
||||||
|
<option value="" selected> Select a Format </option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">Import File </label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="controls kc-button-input-file" data-ng-show="!files || files.length == 0">
|
||||||
|
<a href="#" class="btn btn-default"><span class="kc-icon-upload">Icon: Upload</span>Choose a File...</a>
|
||||||
|
<input id="import-file" type="file" class="transparent" 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="pull-right form-actions" data-ng-show="files.length > 0">
|
||||||
|
<button type="submit" data-ng-click="clearFileSelect()" class="btn btn-lg btn-default">Cancel</button>
|
||||||
|
<button type="submit" data-ng-click="uploadFile()" class="btn btn-lg btn-primary">Import</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -19,7 +19,8 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<a class="btn btn-primary" href="#/create/application/{{realm.realm}}">Add Application</a>
|
<a class="btn btn-primary" href="#/import/application/{{realm.realm}}" data-ng-show="importButton">Import</a>
|
||||||
|
<a class="btn btn-primary" href="#/create/application/{{realm.realm}}">Create</a>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||||
|
<div id="content-area" class="col-sm-9" role="main">
|
||||||
|
<kc-navigation-application></kc-navigation-application>
|
||||||
|
<div id="content">
|
||||||
|
<ol class="breadcrumb" data-ng-hide="create">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/saml/keys">SAML Keys</a></li>
|
||||||
|
<li class="active">SAML {{keyType}} Key Export</li>
|
||||||
|
</ol>
|
||||||
|
<h2><span>{{application.name}}</span> SAML {{keyType}} Key Export <span tooltip-placement="right" tooltip="Export Appliations key and certificate to file." class="fa fa-info-circle"></span></h2>
|
||||||
|
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<fieldset class="form-group col-sm-10">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="downloadKeyFormat">Archive Format</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="select-kc">
|
||||||
|
<select id="downloadKeyFormat"
|
||||||
|
ng-model="jks.format"
|
||||||
|
ng-options="f for f in keyFormats">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Java keystore or PKCS12 archive format." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="keyAlias">Key Alias</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="text" id="keyAlias" name="keyAlias" data-ng-model="jks.keyAlias" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Archive alias for your private key and certificate." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-hide="!keyInfo.privateKey">
|
||||||
|
<label class="col-sm-2 control-label" for="keyPassword">Key Password</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="password" id="keyPassword" name="keyPassword" data-ng-model="jks.keyPassword" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Password to access the private key in the archive" class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="realmAlias">Realm Certificate Alias</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="text" id="realmAlias" name="realmAlias" data-ng-model="jks.realmAlias" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Realm certificate is stored in archive too. This is the alias to it." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="storePassword">Store Password</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="password" id="storePassword" name="storePassword" data-ng-model="jks.storePassword" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Password to access the archive itself" class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="access.manageRealm">
|
||||||
|
<div class="pull-right">
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-click="download()">Download</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,59 @@
|
||||||
|
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||||
|
<div id="content-area" class="col-sm-9" role="main">
|
||||||
|
<kc-navigation-application></kc-navigation-application>
|
||||||
|
<div id="content">
|
||||||
|
<ol class="breadcrumb" data-ng-hide="create">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/saml/keys">SAML Keys</a></li>
|
||||||
|
<li class="active">SAML {{keyType}} Key Import</li>
|
||||||
|
</ol>
|
||||||
|
<h2><span>{{application.name}}</span> SAML {{keyType}} Key Import <span tooltip-placement="right" tooltip="Upload Key." class="fa fa-info-circle"></span></h2>
|
||||||
|
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="uploadKeyFormat">Archive Format</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="select-kc">
|
||||||
|
<select id="uploadKeyFormat"
|
||||||
|
ng-model="uploadKeyFormat"
|
||||||
|
ng-options="f for f in keyFormats">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Java keystore or PKCS12 archive format." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="uploadKeyAlias">Key Alias</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="text" id="uploadKeyAlias" name="uploadKeyAlias" data-ng-model="uploadKeyAlias" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Archive alias for your certificate." class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="uploadStorePassword">Store Password</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="password" id="uploadStorePassword" name="uploadStorePassword" data-ng-model="uploadStorePassword" autofocus required>
|
||||||
|
</div>
|
||||||
|
<span tooltip-placement="right" tooltip="Password to access the archive itself" class="fa fa-info-circle"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">Import File </label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="controls kc-button-input-file" data-ng-show="!files || files.length == 0">
|
||||||
|
<a href="#" class="btn btn-default"><span class="kc-icon-upload">Icon: Upload</span>Choose a File...</a>
|
||||||
|
<input id="import-file" type="file" class="transparent" 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="pull-right form-actions" data-ng-show="files.length > 0">
|
||||||
|
<button type="submit" data-ng-click="clearFileSelect()" class="btn btn-lg btn-default">Cancel</button>
|
||||||
|
<button type="submit" data-ng-click="uploadFile()" class="btn btn-lg btn-primary">Import</button>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,66 @@
|
||||||
|
<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
|
||||||
|
<div id="content-area" class="col-sm-9" role="main">
|
||||||
|
<kc-navigation-application></kc-navigation-application>
|
||||||
|
<div id="content">
|
||||||
|
<ol class="breadcrumb" data-ng-hide="create">
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
|
||||||
|
<li><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">{{application.name}}</a></li>
|
||||||
|
<li class="active">SAML Keys</li>
|
||||||
|
</ol>
|
||||||
|
<h2><span>{{application.name}}</span> SAML Keys <span tooltip-placement="right" tooltip="Application certificates used to sign and encrypt documents." class="fa fa-info-circle"></span></h2>
|
||||||
|
<form class="form-horizontal" name="keyForm" novalidate kc-read-only="!access.manageRealm">
|
||||||
|
<fieldset class="form-group col-sm-10" data-ng-show="application.attributes['saml.client.signature'] == 'true'">
|
||||||
|
<legend uncollapsed><span class="text">Signing Key</span> <span tooltip-placement="right" tooltip="SAML Signing Key." class="fa fa-info-circle"></span></legend>
|
||||||
|
<div class="form-group" data-ng-hide="!signingKeyInfo.privateKey">
|
||||||
|
<label class="col-sm-2 control-label" for="signingPrivateKey">Private key</label>
|
||||||
|
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea type="text" id="signingPrivateKey" name="signingPrivateKey" class="form-control" rows="5"
|
||||||
|
kc-select-action="click" readonly>{{signingKeyInfo.privateKey}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-hide="!signingKeyInfo.certificate">
|
||||||
|
<label class="col-sm-2 control-label" for="signingCert">Certificate</label>
|
||||||
|
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea type="text" id="signingCert" name="signingCert" class="form-control" rows="5"
|
||||||
|
kc-select-action="click" readonly>{{signingKeyInfo.certificate}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="access.manageRealm">
|
||||||
|
<div class="pull-right">
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-click="generateSigningKey()">Generate new keys</button>
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-click="importSigningKey()">Import</button>
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-hide="!signingKeyInfo.certificate" data-ng-click="exportSigningKey()">Export</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="form-group col-sm-10" data-ng-show="application.attributes['saml.encrypt'] == 'true'">
|
||||||
|
<legend uncollapsed><span class="text">Encryption Key</span> <span tooltip-placement="right" tooltip="SAML Encryption Key." class="fa fa-info-circle"></span></legend>
|
||||||
|
<div class="form-group" data-ng-hide="!encryptionKeyInfo.privateKey">
|
||||||
|
<label class="col-sm-2 control-label" for="encryptionPrivateKey">Private key</label>
|
||||||
|
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea type="text" id="encryptionPrivateKey" name="encryptionPrivateKey" class="form-control" rows="5"
|
||||||
|
kc-select-action="click" readonly>{{encryptionKeyInfo.privateKey}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-hide="!encryptionKeyInfo.certificate">
|
||||||
|
<label class="col-sm-2 control-label" for="encryptionCert">Certificate</label>
|
||||||
|
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea type="text" id="encryptionCert" name="encryptionCert" class="form-control" rows="5"
|
||||||
|
kc-select-action="click" readonly>{{encryptionKeyInfo.certificate}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" data-ng-show="access.manageRealm">
|
||||||
|
<div class="pull-right">
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-click="generateEncryptionKey()">Generate new keys</button>
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-click="importEncryptionKey()">Import</button>
|
||||||
|
<button class="btn btn-primary" type="submit" data-ng-hide="!encryptionKeyInfo.certificate" data-ng-click="exportEncryptionKey()">Export</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -1,7 +1,7 @@
|
||||||
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
<ul class="nav nav-tabs nav-tabs-pf" data-ng-show="!create">
|
||||||
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">Settings</a></li>
|
<li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}">Settings</a></li>
|
||||||
<li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.publicClient && application.protocol != 'saml'"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/credentials">Credentials</a></li>
|
<li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!application.publicClient && application.protocol != 'saml'"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/credentials">Credentials</a></li>
|
||||||
<li ng-class="{active: path[4] == 'certificate'}" data-ng-show="application.protocol == 'saml' && application.attributes['saml.client.signature'] == 'true'"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/certificate">Application Keys</a></li>
|
<li ng-class="{active: path[4] == 'saml'}" data-ng-show="application.protocol == 'saml' && (application.attributes['saml.client.signature'] == 'true' || application.attributes['saml.encrypt'] == 'true')"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/saml/keys">SAML Keys</a></li>
|
||||||
<li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
|
<li ng-class="{active: path[4] == 'roles'}"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/roles">Roles</a></li>
|
||||||
<li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/claims">Claims</a></li>
|
<li ng-class="{active: path[4] == 'claims'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/claims">Claims</a></li>
|
||||||
<li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
|
<li ng-class="{active: path[4] == 'scope-mappings'}" data-ng-show="!application.bearerOnly"><a href="#/realms/{{realm.realm}}/applications/{{application.id}}/scope-mappings">Scope</a></li>
|
||||||
|
|
|
@ -93,8 +93,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
log.info("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
log.debug("**** using " + AdapterConstants.AUTH_DATA_PARAM_NAME);
|
||||||
log.info(json);
|
log.debug(json);
|
||||||
return new ByteArrayInputStream(json.getBytes());
|
return new ByteArrayInputStream(json.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
if (is == null) {
|
if (is == null) {
|
||||||
String path = context.getServletContext().getInitParameter("keycloak.config.file");
|
String path = context.getServletContext().getInitParameter("keycloak.config.file");
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
log.info("**** using /WEB-INF/keycloak.json");
|
log.debug("**** using /WEB-INF/keycloak.json");
|
||||||
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
|
is = context.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json");
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
@ -165,7 +165,7 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
||||||
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
|
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
|
||||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||||
if (deployment == null || !deployment.isConfigured()) {
|
if (deployment == null || !deployment.isConfigured()) {
|
||||||
log.info("*** deployment isn't configured return false");
|
log.debug("*** deployment isn't configured return false");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
|
AdapterTokenStore tokenStore = getTokenStore(request, facade, deployment);
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
<description />
|
<description />
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
<version>${jboss.logging.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.apache.catalina.Valve;
|
||||||
import org.apache.catalina.connector.Request;
|
import org.apache.catalina.connector.Request;
|
||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
import org.apache.catalina.valves.ValveBase;
|
import org.apache.catalina.valves.ValveBase;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.AdapterDeploymentContext;
|
import org.keycloak.adapters.AdapterDeploymentContext;
|
||||||
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
import org.keycloak.adapters.AuthenticatedActionsHandler;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
@ -12,7 +13,6 @@ import org.keycloak.adapters.KeycloakDeployment;
|
||||||
import javax.management.ObjectName;
|
import javax.management.ObjectName;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pre-installed actions that must be authenticated
|
* Pre-installed actions that must be authenticated
|
||||||
|
@ -22,16 +22,16 @@ import java.util.logging.Logger;
|
||||||
* CORS Origin Check and Response headers
|
* CORS Origin Check and Response headers
|
||||||
* k_query_bearer_token: Get bearer token from server for Javascripts CORS requests
|
* k_query_bearer_token: Get bearer token from server for Javascripts CORS requests
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class AuthenticatedActionsValve extends ValveBase {
|
public class AuthenticatedActionsValve extends ValveBase {
|
||||||
private static final Logger log = Logger.getLogger(""+AuthenticatedActionsValve.class);
|
private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
|
||||||
protected AdapterDeploymentContext deploymentContext;
|
protected AdapterDeploymentContext deploymentContext;
|
||||||
|
|
||||||
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container, ObjectName controller) {
|
public AuthenticatedActionsValve(AdapterDeploymentContext deploymentContext, Valve next, Container container) {
|
||||||
this.deploymentContext = deploymentContext;
|
this.deploymentContext = deploymentContext;
|
||||||
if (next == null) throw new RuntimeException("WTF is next null?!");
|
if (next == null) throw new RuntimeException("Next valve is null!!!");
|
||||||
setNext(next);
|
setNext(next);
|
||||||
setContainer(container);
|
setContainer(container);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public class AuthenticatedActionsValve extends ValveBase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||||
log.finer("AuthenticatedActionsValve.invoke" + request.getRequestURI());
|
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
|
||||||
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
|
CatalinaHttpFacade facade = new CatalinaHttpFacade(request, response);
|
||||||
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
|
||||||
if (deployment != null && deployment.isConfigured()) {
|
if (deployment != null && deployment.isConfigured()) {
|
||||||
|
@ -51,6 +51,4 @@ public class AuthenticatedActionsValve extends ValveBase {
|
||||||
}
|
}
|
||||||
getNext().invoke(request, response);
|
getNext().invoke(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -5,20 +5,19 @@ import org.apache.catalina.Session;
|
||||||
import org.apache.catalina.SessionEvent;
|
import org.apache.catalina.SessionEvent;
|
||||||
import org.apache.catalina.SessionListener;
|
import org.apache.catalina.SessionListener;
|
||||||
import org.apache.catalina.realm.GenericPrincipal;
|
import org.apache.catalina.realm.GenericPrincipal;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages relationship to users and sessions so that forced admin logout can be implemented
|
* Manages relationship to users and sessions so that forced admin logout can be implemented
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class CatalinaUserSessionManagement implements SessionListener {
|
public class CatalinaUserSessionManagement implements SessionListener {
|
||||||
|
private static final Logger log = Logger.getLogger(CatalinaUserSessionManagement.class);
|
||||||
private static final Logger log = Logger.getLogger(""+CatalinaUserSessionManagement.class);
|
|
||||||
|
|
||||||
public void login(Session session) {
|
public void login(Session session) {
|
||||||
session.addSessionListener(this);
|
session.addSessionListener(this);
|
||||||
|
@ -32,7 +31,7 @@ public class CatalinaUserSessionManagement implements SessionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
|
public void logoutHttpSessions(Manager sessionManager, List<String> sessionIds) {
|
||||||
log.fine("logoutHttpSessions: " + sessionIds);
|
log.debug("logoutHttpSessions: " + sessionIds);
|
||||||
|
|
||||||
for (String sessionId : sessionIds) {
|
for (String sessionId : sessionIds) {
|
||||||
logoutSession(sessionManager, sessionId);
|
logoutSession(sessionManager, sessionId);
|
||||||
|
@ -40,14 +39,13 @@ public class CatalinaUserSessionManagement implements SessionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void logoutSession(Manager manager, String httpSessionId) {
|
protected void logoutSession(Manager manager, String httpSessionId) {
|
||||||
log.fine("logoutHttpSession: " + httpSessionId);
|
log.debug("logoutHttpSession: " + httpSessionId);
|
||||||
|
|
||||||
Session session;
|
Session session;
|
||||||
try {
|
try {
|
||||||
session = manager.findSession(httpSessionId);
|
session = manager.findSession(httpSessionId);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
log.warning("IO exception when looking for session " + httpSessionId);
|
log.warn("IO exception when looking for session " + httpSessionId, ioe);
|
||||||
ioe.printStackTrace();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +56,7 @@ public class CatalinaUserSessionManagement implements SessionListener {
|
||||||
try {
|
try {
|
||||||
session.expire();
|
session.expire();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warning("Session not present or already invalidated.");
|
log.warnf("Session not present or already invalidated.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +68,7 @@ public class CatalinaUserSessionManagement implements SessionListener {
|
||||||
|
|
||||||
// Look up the single session id associated with this session (if any)
|
// Look up the single session id associated with this session (if any)
|
||||||
Session session = event.getSession();
|
Session session = event.getSession();
|
||||||
log.fine("Session " + session.getId() + " destroyed");
|
log.debugf("Session %s destroyed", session.getId());
|
||||||
|
|
||||||
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
|
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
|
||||||
if (principal == null) return;
|
if (principal == null) return;
|
||||||
|
|
|
@ -2,17 +2,17 @@ package org.keycloak.adapters.tomcat7;
|
||||||
|
|
||||||
import org.apache.catalina.connector.Request;
|
import org.apache.catalina.connector.Request;
|
||||||
import org.apache.catalina.connector.Response;
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.adapters.KeycloakDeployment;
|
import org.keycloak.adapters.KeycloakDeployment;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:ungarida@gmail.com">Davide Ungari</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class CorsPreflightChecker {
|
public class CorsPreflightChecker {
|
||||||
private static final Logger log = Logger.getLogger(""+CorsPreflightChecker.class);
|
private static final Logger log = Logger.getLogger(CorsPreflightChecker.class);
|
||||||
protected KeycloakDeployment deployment;
|
protected KeycloakDeployment deployment;
|
||||||
|
|
||||||
public CorsPreflightChecker(KeycloakDeployment deployment) {
|
public CorsPreflightChecker(KeycloakDeployment deployment) {
|
||||||
|
@ -20,17 +20,17 @@ public class CorsPreflightChecker {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkCorsPreflight(Request request, Response response) {
|
public boolean checkCorsPreflight(Request request, Response response) {
|
||||||
log.finer("checkCorsPreflight " + request.getRequestURI());
|
log.debugv("checkCorsPreflight {0}", request.getRequestURI());
|
||||||
if (!request.getMethod().equalsIgnoreCase("OPTIONS")) {
|
if (!request.getMethod().equalsIgnoreCase("OPTIONS")) {
|
||||||
log.finer("checkCorsPreflight: not options ");
|
log.debug("checkCorsPreflight: not options ");
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (request.getHeader("Origin") == null) {
|
if (request.getHeader("Origin") == null) {
|
||||||
log.finer("checkCorsPreflight: no origin header");
|
log.debug("checkCorsPreflight: no origin header");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log.finer("Preflight request returning");
|
log.debug("Preflight request returning");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
String origin = request.getHeader("Origin");
|
String origin = request.getHeader("Origin");
|
||||||
response.setHeader("Access-Control-Allow-Origin", origin);
|
response.setHeader("Access-Control-Allow-Origin", origin);
|
||||||
|
|
|
@ -132,6 +132,7 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void generateClientKeyPairCertificate(ClientModel client) {
|
public static void generateClientKeyPairCertificate(ClientModel client) {
|
||||||
|
String subject = client.getClientId();
|
||||||
KeyPair keyPair = null;
|
KeyPair keyPair = null;
|
||||||
try {
|
try {
|
||||||
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||||
|
@ -140,7 +141,7 @@ public final class KeycloakModelUtils {
|
||||||
}
|
}
|
||||||
X509Certificate certificate = null;
|
X509Certificate certificate = null;
|
||||||
try {
|
try {
|
||||||
certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, client.getClientId());
|
certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,11 @@
|
||||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||||
</properties>
|
</properties>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-multipart-provider</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.keycloak.protocol.saml;
|
||||||
|
|
||||||
|
import org.keycloak.exportimport.ApplicationImporter;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class EntityDescriptorImporter implements ApplicationImporter {
|
||||||
|
@Override
|
||||||
|
public Object createJaxrsService(RealmModel realm, RealmAuth auth) {
|
||||||
|
return new EntityDescriptorImporterService(realm, auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.keycloak.protocol.saml;
|
||||||
|
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.exportimport.ApplicationImporter;
|
||||||
|
import org.keycloak.exportimport.ApplicationImporterFactory;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class EntityDescriptorImporterFactory implements ApplicationImporterFactory {
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "SAML 2.0 Entity Descriptor";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApplicationImporter create(KeycloakSession session) {
|
||||||
|
return new EntityDescriptorImporter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "saml2-entity-descriptor";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
package org.keycloak.protocol.saml;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.plugins.providers.multipart.InputPart;
|
||||||
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
import org.picketlink.common.constants.JBossSAMLURIConstants;
|
||||||
|
import org.picketlink.common.exceptions.ConfigurationException;
|
||||||
|
import org.picketlink.common.exceptions.ParsingException;
|
||||||
|
import org.picketlink.common.exceptions.ProcessingException;
|
||||||
|
import org.picketlink.identity.federation.core.parsers.saml.SAMLParser;
|
||||||
|
import org.picketlink.identity.federation.core.saml.v2.util.SAMLMetadataUtil;
|
||||||
|
import org.picketlink.identity.federation.core.util.CoreConfigUtil;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.EndpointType;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.EntitiesDescriptorType;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.EntityDescriptorType;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.KeyDescriptorType;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.KeyTypes;
|
||||||
|
import org.picketlink.identity.federation.saml.v2.metadata.SPSSODescriptorType;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class EntityDescriptorImporterService {
|
||||||
|
protected RealmModel realm;
|
||||||
|
protected RealmAuth auth;
|
||||||
|
|
||||||
|
public EntityDescriptorImporterService(RealmModel realm, RealmAuth auth) {
|
||||||
|
this.realm = realm;
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("upload")
|
||||||
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||||
|
public void updateEntityDescriptor(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
||||||
|
auth.requireManage();
|
||||||
|
|
||||||
|
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
||||||
|
List<InputPart> inputParts = uploadForm.get("file");
|
||||||
|
|
||||||
|
InputStream is = inputParts.get(0).getBody(InputStream.class, null);
|
||||||
|
|
||||||
|
loadEntityDescriptors(is, realm);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadEntityDescriptors(InputStream is, RealmModel realm) {
|
||||||
|
Object metadata = null;
|
||||||
|
try {
|
||||||
|
metadata = new SAMLParser().parse(is);
|
||||||
|
} catch (ParsingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
EntitiesDescriptorType entities;
|
||||||
|
|
||||||
|
if (EntitiesDescriptorType.class.isInstance(metadata)) {
|
||||||
|
entities = (EntitiesDescriptorType) metadata;
|
||||||
|
} else {
|
||||||
|
entities = new EntitiesDescriptorType();
|
||||||
|
entities.addEntityDescriptor(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object o : entities.getEntityDescriptor()) {
|
||||||
|
EntityDescriptorType entity = (EntityDescriptorType)o;
|
||||||
|
String entityId = entity.getEntityID();
|
||||||
|
ApplicationModel app = realm.addApplication(entityId);
|
||||||
|
app.setFullScopeAllowed(true);
|
||||||
|
app.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
|
||||||
|
app.setAttribute(SamlProtocol.SAML_SERVER_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE); // default to true
|
||||||
|
app.setAttribute(SamlProtocol.SAML_SIGNATURE_ALGORITHM, SignatureAlgorithm.RSA_SHA256.toString());
|
||||||
|
app.setAttribute(SamlProtocol.SAML_AUTHNSTATEMENT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
||||||
|
SPSSODescriptorType spDescriptorType = CoreConfigUtil.getSPDescriptor(entity);
|
||||||
|
if (spDescriptorType.isWantAssertionsSigned()) {
|
||||||
|
app.setAttribute(SamlProtocol.SAML_ASSERTION_SIGNATURE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
||||||
|
}
|
||||||
|
String adminUrl = getLogoutLocation(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
|
||||||
|
if (adminUrl != null) app.setManagementUrl(adminUrl);
|
||||||
|
|
||||||
|
String urlPattern = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get());
|
||||||
|
if (urlPattern == null) {
|
||||||
|
urlPattern = CoreConfigUtil.getServiceURL(spDescriptorType, JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get());
|
||||||
|
}
|
||||||
|
if (urlPattern != null) {
|
||||||
|
app.addRedirectUri(urlPattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (KeyDescriptorType keyDescriptor : spDescriptorType.getKeyDescriptor()) {
|
||||||
|
X509Certificate cert = null;
|
||||||
|
try {
|
||||||
|
cert = SAMLMetadataUtil.getCertificate(keyDescriptor);
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (ProcessingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
String certPem = KeycloakModelUtils.getPemFromCertificate(cert);
|
||||||
|
if (keyDescriptor.getUse() == KeyTypes.SIGNING) {
|
||||||
|
app.setAttribute(SamlProtocol.SAML_CLIENT_SIGNATURE_ATTRIBUTE, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
||||||
|
app.setAttribute(SamlProtocol.SAML_SIGNING_CERTIFICATE_ATTRIBUTE, certPem);
|
||||||
|
} else if (keyDescriptor.getUse() == KeyTypes.ENCRYPTION) {
|
||||||
|
app.setAttribute(SamlProtocol.SAML_ENCRYPT, SamlProtocol.ATTRIBUTE_TRUE_VALUE);
|
||||||
|
app.setAttribute(SamlProtocol.SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE, certPem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getLogoutLocation(SPSSODescriptorType idp, String bindingURI) {
|
||||||
|
String logoutResponseLocation = null;
|
||||||
|
|
||||||
|
List<EndpointType> endpoints = idp.getSingleLogoutService();
|
||||||
|
for (EndpointType endpoint : endpoints) {
|
||||||
|
if (endpoint.getBinding().toString().equals(bindingURI)) {
|
||||||
|
if (endpoint.getLocation() != null) {
|
||||||
|
logoutResponseLocation = endpoint.getLocation().toString();
|
||||||
|
} else {
|
||||||
|
logoutResponseLocation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return logoutResponseLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -17,8 +17,8 @@ import org.keycloak.protocol.LoginProtocol;
|
||||||
import org.keycloak.services.managers.ClientSessionCode;
|
import org.keycloak.services.managers.ClientSessionCode;
|
||||||
import org.keycloak.services.managers.ResourceAdminManager;
|
import org.keycloak.services.managers.ResourceAdminManager;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
|
import org.keycloak.services.resources.admin.ClientAttributeCertificateResource;
|
||||||
import org.keycloak.services.resources.flows.Flows;
|
import org.keycloak.services.resources.flows.Flows;
|
||||||
import org.keycloak.util.PemUtils;
|
|
||||||
import org.picketlink.common.constants.GeneralConstants;
|
import org.picketlink.common.constants.GeneralConstants;
|
||||||
import org.picketlink.common.constants.JBossSAMLURIConstants;
|
import org.picketlink.common.constants.JBossSAMLURIConstants;
|
||||||
import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants;
|
import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants;
|
||||||
|
@ -35,6 +35,13 @@ import java.security.PublicKey;
|
||||||
*/
|
*/
|
||||||
public class SamlProtocol implements LoginProtocol {
|
public class SamlProtocol implements LoginProtocol {
|
||||||
protected static final Logger logger = Logger.getLogger(SamlProtocol.class);
|
protected static final Logger logger = Logger.getLogger(SamlProtocol.class);
|
||||||
|
|
||||||
|
|
||||||
|
public static final String ATTRIBUTE_TRUE_VALUE = "true";
|
||||||
|
public static final String ATTRIBUTE_FALSE_VALUE = "false";
|
||||||
|
public static final String SAML_SIGNING_CERTIFICATE_ATTRIBUTE = "saml.signing." + ClientAttributeCertificateResource.X509CERTIFICATE;
|
||||||
|
public static final String SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE = "saml.encryption." + ClientAttributeCertificateResource.X509CERTIFICATE;
|
||||||
|
public static final String SAML_CLIENT_SIGNATURE_ATTRIBUTE = "saml.client.signature";
|
||||||
public static final String LOGIN_PROTOCOL = "saml";
|
public static final String LOGIN_PROTOCOL = "saml";
|
||||||
public static final String SAML_BINDING = "saml_binding";
|
public static final String SAML_BINDING = "saml_binding";
|
||||||
public static final String SAML_POST_BINDING = "post";
|
public static final String SAML_POST_BINDING = "post";
|
||||||
|
@ -46,7 +53,7 @@ public class SamlProtocol implements LoginProtocol {
|
||||||
public static final String SAML_SIGNATURE_ALGORITHM = "saml.signature.algorithm";
|
public static final String SAML_SIGNATURE_ALGORITHM = "saml.signature.algorithm";
|
||||||
public static final String SAML_ENCRYPT = "saml.encrypt";
|
public static final String SAML_ENCRYPT = "saml.encrypt";
|
||||||
public static final String SAML_FORCE_POST_BINDING = "saml.force.post.binding";
|
public static final String SAML_FORCE_POST_BINDING = "saml.force.post.binding";
|
||||||
public static final String REQUEST_ID = "REQUEST_ID";
|
public static final String SAML_REQUEST_ID = "SAML_REQUEST_ID";
|
||||||
|
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
|
||||||
|
@ -114,7 +121,7 @@ public class SamlProtocol implements LoginProtocol {
|
||||||
public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) {
|
public Response authenticated(UserSessionModel userSession, ClientSessionCode accessCode) {
|
||||||
ClientSessionModel clientSession = accessCode.getClientSession();
|
ClientSessionModel clientSession = accessCode.getClientSession();
|
||||||
ClientModel client = clientSession.getClient();
|
ClientModel client = clientSession.getClient();
|
||||||
String requestID = clientSession.getNote(REQUEST_ID);
|
String requestID = clientSession.getNote(SAML_REQUEST_ID);
|
||||||
String relayState = clientSession.getNote(GeneralConstants.RELAY_STATE);
|
String relayState = clientSession.getNote(GeneralConstants.RELAY_STATE);
|
||||||
String redirectUri = clientSession.getRedirectUri();
|
String redirectUri = clientSession.getRedirectUri();
|
||||||
String responseIssuer = getResponseIssuer(realm);
|
String responseIssuer = getResponseIssuer(realm);
|
||||||
|
@ -155,7 +162,7 @@ public class SamlProtocol implements LoginProtocol {
|
||||||
if (requiresEncryption(client)) {
|
if (requiresEncryption(client)) {
|
||||||
PublicKey publicKey = null;
|
PublicKey publicKey = null;
|
||||||
try {
|
try {
|
||||||
publicKey = PemUtils.decodePublicKey(client.getAttribute(ClientModel.PUBLIC_KEY));
|
publicKey = SamlProtocolUtils.getEncryptionValidationKey(client);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("failed", e);
|
logger.error("failed", e);
|
||||||
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
|
return Flows.forwardToSecurityFailurePage(session, realm, uriInfo, "Failed to process response");
|
||||||
|
|
|
@ -6,11 +6,9 @@ import org.keycloak.util.PemUtils;
|
||||||
import org.picketlink.common.exceptions.ProcessingException;
|
import org.picketlink.common.exceptions.ProcessingException;
|
||||||
import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature;
|
import org.picketlink.identity.federation.api.saml.v2.sig.SAML2Signature;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.Certificate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -19,11 +17,11 @@ import java.security.cert.X509Certificate;
|
||||||
public class SamlProtocolUtils {
|
public class SamlProtocolUtils {
|
||||||
|
|
||||||
public static void verifyDocumentSignature(ClientModel client, Document document) throws VerificationException {
|
public static void verifyDocumentSignature(ClientModel client, Document document) throws VerificationException {
|
||||||
if (!"true".equals(client.getAttribute("saml.client.signature"))) {
|
if (!"true".equals(client.getAttribute(SamlProtocol.SAML_CLIENT_SIGNATURE_ATTRIBUTE))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SAML2Signature saml2Signature = new SAML2Signature();
|
SAML2Signature saml2Signature = new SAML2Signature();
|
||||||
PublicKey publicKey = getPublicKey(client);
|
PublicKey publicKey = getSignatureValidationKey(client);
|
||||||
try {
|
try {
|
||||||
if (!saml2Signature.validate(document, publicKey)) {
|
if (!saml2Signature.validate(document, publicKey)) {
|
||||||
throw new VerificationException("Invalid signature on document");
|
throw new VerificationException("Invalid signature on document");
|
||||||
|
@ -33,16 +31,24 @@ public class SamlProtocolUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PublicKey getPublicKey(ClientModel client) throws VerificationException {
|
public static PublicKey getSignatureValidationKey(ClientModel client) throws VerificationException {
|
||||||
String publicKeyPem = client.getAttribute(ClientModel.PUBLIC_KEY);
|
return getPublicKey(client, SamlProtocol.SAML_SIGNING_CERTIFICATE_ATTRIBUTE);
|
||||||
if (publicKeyPem == null) throw new VerificationException("Client does not have a public key.");
|
}
|
||||||
PublicKey publicKey = null;
|
|
||||||
|
public static PublicKey getEncryptionValidationKey(ClientModel client) throws VerificationException {
|
||||||
|
return getPublicKey(client, SamlProtocol.SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicKey getPublicKey(ClientModel client, String attribute) throws VerificationException {
|
||||||
|
String certPem = client.getAttribute(attribute);
|
||||||
|
if (certPem == null) throw new VerificationException("Client does not have a public key.");
|
||||||
|
Certificate cert = null;
|
||||||
try {
|
try {
|
||||||
publicKey = PemUtils.decodePublicKey(publicKeyPem);
|
cert = PemUtils.decodeCertificate(certPem);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new VerificationException("Could not decode public key", e);
|
throw new VerificationException("Could not decode cert", e);
|
||||||
}
|
}
|
||||||
return publicKey;
|
return cert.getPublicKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ public class SamlService {
|
||||||
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
|
||||||
clientSession.setNote(SamlProtocol.SAML_BINDING, getBindingType());
|
clientSession.setNote(SamlProtocol.SAML_BINDING, getBindingType());
|
||||||
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
|
clientSession.setNote(GeneralConstants.RELAY_STATE, relayState);
|
||||||
clientSession.setNote(SamlProtocol.REQUEST_ID, requestAbstractType.getID());
|
clientSession.setNote(SamlProtocol.SAML_REQUEST_ID, requestAbstractType.getID());
|
||||||
|
|
||||||
Response response = authManager.checkNonFormAuthentication(session, clientSession, realm, uriInfo, request, clientConnection, headers, event);
|
Response response = authManager.checkNonFormAuthentication(session, clientSession, realm, uriInfo, request, clientConnection, headers, event);
|
||||||
if (response != null) return response;
|
if (response != null) return response;
|
||||||
|
@ -309,7 +309,7 @@ public class SamlService {
|
||||||
// todo maybe a flag?
|
// todo maybe a flag?
|
||||||
// SamlProtocolUtils.verifyDocumentSignature(client, documentHolder.getSamlDocument());
|
// SamlProtocolUtils.verifyDocumentSignature(client, documentHolder.getSamlDocument());
|
||||||
|
|
||||||
PublicKey publicKey = SamlProtocolUtils.getPublicKey(client);
|
PublicKey publicKey = SamlProtocolUtils.getSignatureValidationKey(client);
|
||||||
|
|
||||||
|
|
||||||
UriBuilder builder = UriBuilder.fromPath("/")
|
UriBuilder builder = UriBuilder.fromPath("/")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
org.keycloak.protocol.saml.EntityDescriptorImporterFactory
|
26
services/src/main/java/org/keycloak/exportimport/ApplicationImportSpi.java
Executable file
26
services/src/main/java/org/keycloak/exportimport/ApplicationImportSpi.java
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
import org.keycloak.provider.Spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class ApplicationImportSpi implements Spi {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "application-import";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends Provider> getProviderClass() {
|
||||||
|
return ApplicationImporter.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||||
|
return ApplicationImporterFactory.class;
|
||||||
|
}
|
||||||
|
}
|
15
services/src/main/java/org/keycloak/exportimport/ApplicationImporter.java
Executable file
15
services/src/main/java/org/keycloak/exportimport/ApplicationImporter.java
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.provider.Provider;
|
||||||
|
import org.keycloak.services.resources.admin.RealmAuth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider plugin interface for importing applications from an arbitrary configuration format
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface ApplicationImporter extends Provider {
|
||||||
|
public Object createJaxrsService(RealmModel realm, RealmAuth auth);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.keycloak.exportimport;
|
||||||
|
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider plugin interface for importing applications from an arbitrary configuration format
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public interface ApplicationImporterFactory extends ProviderFactory<ApplicationImporter> {
|
||||||
|
public String getDisplayName();
|
||||||
|
}
|
|
@ -120,9 +120,9 @@ public class ApplicationResource {
|
||||||
return ModelToRepresentation.toRepresentation(application);
|
return ModelToRepresentation.toRepresentation(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("certificates")
|
@Path("certificates/{attr}")
|
||||||
public ClientCertificateResource getCertficateResource() {
|
public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix) {
|
||||||
return new ClientCertificateResource(realm, auth, application, session);
|
return new ClientAttributeCertificateResource(realm, auth, application, session, attributePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,11 @@ import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
|
||||||
import org.jboss.resteasy.spi.BadRequestException;
|
import org.jboss.resteasy.spi.BadRequestException;
|
||||||
import org.jboss.resteasy.spi.NotAcceptableException;
|
import org.jboss.resteasy.spi.NotAcceptableException;
|
||||||
import org.jboss.resteasy.spi.NotFoundException;
|
import org.jboss.resteasy.spi.NotFoundException;
|
||||||
import org.keycloak.models.AdminRoles;
|
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.util.CertificateUtils;
|
||||||
import org.keycloak.services.ForbiddenException;
|
|
||||||
import org.keycloak.services.managers.RealmManager;
|
|
||||||
import org.keycloak.services.resources.flows.Flows;
|
|
||||||
import org.keycloak.util.JsonSerialization;
|
|
||||||
import org.keycloak.util.PemUtils;
|
import org.keycloak.util.PemUtils;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
|
@ -24,27 +18,20 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.security.KeyPair;
|
||||||
import java.net.URI;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -53,17 +40,26 @@ import java.util.Map;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class ClientCertificateResource {
|
public class ClientAttributeCertificateResource {
|
||||||
|
public static final String PRIVATE_KEY = "private.key";
|
||||||
|
public static final String X509CERTIFICATE = "certificate";
|
||||||
|
|
||||||
protected RealmModel realm;
|
protected RealmModel realm;
|
||||||
private RealmAuth auth;
|
private RealmAuth auth;
|
||||||
protected ClientModel client;
|
protected ClientModel client;
|
||||||
protected KeycloakSession session;
|
protected KeycloakSession session;
|
||||||
|
protected String attributePrefix;
|
||||||
|
protected String privateAttribute;
|
||||||
|
protected String certificateAttribute;
|
||||||
|
|
||||||
public ClientCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session) {
|
public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
|
this.attributePrefix = attributePrefix;
|
||||||
|
this.privateAttribute = attributePrefix + "." + PRIVATE_KEY;
|
||||||
|
this.certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ClientKeyPairInfo {
|
public static class ClientKeyPairInfo {
|
||||||
|
@ -79,14 +75,6 @@ public class ClientCertificateResource {
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getPublicKey() {
|
|
||||||
return publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPublicKey(String publicKey) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCertificate() {
|
public String getCertificate() {
|
||||||
return certificate;
|
return certificate;
|
||||||
}
|
}
|
||||||
|
@ -101,9 +89,8 @@ public class ClientCertificateResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ClientKeyPairInfo getKeyInfo() {
|
public ClientKeyPairInfo getKeyInfo() {
|
||||||
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
||||||
info.setCertificate(client.getAttribute(ClientModel.X509CERTIFICATE));
|
info.setCertificate(client.getAttribute(certificateAttribute));
|
||||||
info.setPrivateKey(client.getAttribute(ClientModel.PRIVATE_KEY));
|
info.setPrivateKey(client.getAttribute(privateAttribute));
|
||||||
info.setPublicKey(client.getAttribute(ClientModel.PUBLIC_KEY));
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,51 +102,79 @@ public class ClientCertificateResource {
|
||||||
public ClientKeyPairInfo generate() {
|
public ClientKeyPairInfo generate() {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
|
|
||||||
|
String subject = client.getClientId();
|
||||||
|
KeyPair keyPair = null;
|
||||||
|
try {
|
||||||
|
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
X509Certificate certificate = null;
|
||||||
|
try {
|
||||||
|
certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
String privateKeyPem = KeycloakModelUtils.getPemFromKey(keyPair.getPrivate());
|
||||||
|
String certPem = KeycloakModelUtils.getPemFromCertificate(certificate);
|
||||||
|
|
||||||
|
client.setAttribute(privateAttribute, privateKeyPem);
|
||||||
|
client.setAttribute(certificateAttribute, certPem);
|
||||||
|
|
||||||
|
|
||||||
KeycloakModelUtils.generateClientKeyPairCertificate(client);
|
KeycloakModelUtils.generateClientKeyPairCertificate(client);
|
||||||
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
||||||
info.setCertificate(client.getAttribute(ClientModel.X509CERTIFICATE));
|
info.setCertificate(client.getAttribute(certificateAttribute));
|
||||||
info.setPrivateKey(client.getAttribute(ClientModel.PRIVATE_KEY));
|
info.setPrivateKey(client.getAttribute(privateAttribute));
|
||||||
info.setPublicKey(client.getAttribute(ClientModel.PUBLIC_KEY));
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("upload/jks")
|
@Path("upload")
|
||||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public ClientKeyPairInfo uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
public ClientKeyPairInfo uploadJks(@Context final UriInfo uriInfo, MultipartFormDataInput input) throws IOException {
|
||||||
auth.requireManage();
|
auth.requireManage();
|
||||||
|
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
||||||
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
|
||||||
List<InputPart> inputParts = uploadForm.get("file");
|
List<InputPart> inputParts = uploadForm.get("file");
|
||||||
|
|
||||||
String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
|
String keystoreFormat = uploadForm.get("keystoreFormat").get(0).getBodyAsString();
|
||||||
String keyAlias = uploadForm.get("keyAlias").get(0).getBodyAsString();
|
String keyAlias = uploadForm.get("keyAlias").get(0).getBodyAsString();
|
||||||
String keyPassword = uploadForm.get("keyPassword").get(0).getBodyAsString();
|
List<InputPart> keyPasswordPart = uploadForm.get("keyPassword");
|
||||||
String storePassword = uploadForm.get("storePassword").get(0).getBodyAsString();
|
char[] keyPassword = keyPasswordPart != null ? keyPasswordPart.get(0).getBodyAsString().toCharArray() : null;
|
||||||
System.out.println("format = '" + keystoreFormat + "'");
|
|
||||||
|
List<InputPart> storePasswordPart = uploadForm.get("storePassword");
|
||||||
|
char[] storePassword = storePasswordPart != null ? storePasswordPart.get(0).getBodyAsString().toCharArray() : null;
|
||||||
PrivateKey privateKey = null;
|
PrivateKey privateKey = null;
|
||||||
X509Certificate certificate = null;
|
X509Certificate certificate = null;
|
||||||
try {
|
try {
|
||||||
KeyStore keyStore = null;
|
KeyStore keyStore = null;
|
||||||
if (keystoreFormat.equals("JKS")) keyStore = KeyStore.getInstance("JKS");
|
if (keystoreFormat.equals("JKS")) keyStore = KeyStore.getInstance("JKS");
|
||||||
else keyStore = KeyStore.getInstance(keystoreFormat, "BC");
|
else keyStore = KeyStore.getInstance(keystoreFormat, "BC");
|
||||||
keyStore.load(inputParts.get(0).getBody(InputStream.class, null), storePassword.toCharArray());
|
keyStore.load(inputParts.get(0).getBody(InputStream.class, null), storePassword);
|
||||||
privateKey = (PrivateKey)keyStore.getKey(keyAlias, keyPassword.toCharArray());
|
try {
|
||||||
|
privateKey = (PrivateKey)keyStore.getKey(keyAlias, keyPassword);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
certificate = (X509Certificate)keyStore.getCertificate(keyAlias);
|
certificate = (X509Certificate)keyStore.getCertificate(keyAlias);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
if (privateKey != null) {
|
||||||
String privateKeyPem = KeycloakModelUtils.getPemFromKey(privateKey);
|
String privateKeyPem = KeycloakModelUtils.getPemFromKey(privateKey);
|
||||||
String publicKeyPem = KeycloakModelUtils.getPemFromKey(certificate.getPublicKey());
|
client.setAttribute(privateAttribute, privateKeyPem);
|
||||||
String certPem = KeycloakModelUtils.getPemFromCertificate(certificate);
|
info.setPrivateKey(privateKeyPem);
|
||||||
client.setAttribute(ClientModel.PRIVATE_KEY, privateKeyPem);
|
} else if (certificate != null) {
|
||||||
client.setAttribute(ClientModel.PUBLIC_KEY, publicKeyPem);
|
client.removeAttribute(privateAttribute);
|
||||||
client.setAttribute(ClientModel.X509CERTIFICATE, certPem);
|
}
|
||||||
|
|
||||||
ClientKeyPairInfo info = new ClientKeyPairInfo();
|
if (certificate != null) {
|
||||||
info.setCertificate(client.getAttribute(ClientModel.X509CERTIFICATE));
|
String certPem = KeycloakModelUtils.getPemFromCertificate(certificate);
|
||||||
info.setPrivateKey(client.getAttribute(ClientModel.PRIVATE_KEY));
|
client.setAttribute(certificateAttribute, certPem);
|
||||||
info.setPublicKey(client.getAttribute(ClientModel.PUBLIC_KEY));
|
info.setCertificate(certPem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -234,10 +249,12 @@ public class ClientCertificateResource {
|
||||||
throw new NotAcceptableException("Only support jks format.");
|
throw new NotAcceptableException("Only support jks format.");
|
||||||
}
|
}
|
||||||
String format = config.getFormat();
|
String format = config.getFormat();
|
||||||
if (client.getAttribute(ClientModel.PRIVATE_KEY) == null) {
|
String privatePem = client.getAttribute(privateAttribute);
|
||||||
|
String certPem = client.getAttribute(certificateAttribute);
|
||||||
|
if (privatePem == null && certPem == null) {
|
||||||
throw new NotFoundException("keypair not generated for client");
|
throw new NotFoundException("keypair not generated for client");
|
||||||
}
|
}
|
||||||
if (config.getKeyPassword() == null) {
|
if (privatePem != null && config.getKeyPassword() == null) {
|
||||||
throw new BadRequestException("Need to specify a key password for jks download");
|
throw new BadRequestException("Need to specify a key password for jks download");
|
||||||
}
|
}
|
||||||
if (config.getStorePassword() == null) {
|
if (config.getStorePassword() == null) {
|
||||||
|
@ -250,13 +267,19 @@ public class ClientCertificateResource {
|
||||||
keyStore.load(null, null);
|
keyStore.load(null, null);
|
||||||
String keyAlias = config.getKeyAlias();
|
String keyAlias = config.getKeyAlias();
|
||||||
if (keyAlias == null) keyAlias = client.getClientId();
|
if (keyAlias == null) keyAlias = client.getClientId();
|
||||||
PrivateKey privateKey = PemUtils.decodePrivateKey(client.getAttribute(ClientModel.PRIVATE_KEY));
|
if (privatePem != null) {
|
||||||
X509Certificate clientCert = PemUtils.decodeCertificate(client.getAttribute(ClientModel.X509CERTIFICATE));
|
PrivateKey privateKey = PemUtils.decodePrivateKey(privatePem);
|
||||||
|
X509Certificate clientCert = PemUtils.decodeCertificate(certPem);
|
||||||
|
|
||||||
|
|
||||||
Certificate[] chain = {clientCert};
|
Certificate[] chain = {clientCert};
|
||||||
|
|
||||||
keyStore.setKeyEntry(keyAlias, privateKey, config.getKeyPassword().trim().toCharArray(), chain);
|
keyStore.setKeyEntry(keyAlias, privateKey, config.getKeyPassword().trim().toCharArray(), chain);
|
||||||
|
} else {
|
||||||
|
X509Certificate clientCert = PemUtils.decodeCertificate(certPem);
|
||||||
|
keyStore.setCertificateEntry(keyAlias, clientCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (config.isRealmCertificate() == null || config.isRealmCertificate().booleanValue()) {
|
if (config.isRealmCertificate() == null || config.isRealmCertificate().booleanValue()) {
|
||||||
X509Certificate certificate = realm.getCertificate();
|
X509Certificate certificate = realm.getCertificate();
|
|
@ -24,6 +24,7 @@ import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.POST;
|
import javax.ws.rs.POST;
|
||||||
import javax.ws.rs.PUT;
|
import javax.ws.rs.PUT;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
import javax.ws.rs.Produces;
|
import javax.ws.rs.Produces;
|
||||||
import javax.ws.rs.core.Context;
|
import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
@ -72,9 +73,9 @@ public class OAuthClientResource {
|
||||||
return new ClaimResource(oauthClient, auth);
|
return new ClaimResource(oauthClient, auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("certificates")
|
@Path("certificates/{attr}")
|
||||||
public ClientCertificateResource getCertficateResource() {
|
public ClientAttributeCertificateResource getCertficateResource(@PathParam("attr") String attributePrefix) {
|
||||||
return new ClientCertificateResource(realm, auth, oauthClient, session);
|
return new ClientAttributeCertificateResource(realm, auth, oauthClient, session, attributePrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.events.Event;
|
||||||
import org.keycloak.events.EventQuery;
|
import org.keycloak.events.EventQuery;
|
||||||
import org.keycloak.events.EventStoreProvider;
|
import org.keycloak.events.EventStoreProvider;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
|
import org.keycloak.exportimport.ApplicationImporter;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
|
@ -73,6 +74,17 @@ public class RealmAdminResource {
|
||||||
auth.init(RealmAuth.Resource.REALM);
|
auth.init(RealmAuth.Resource.REALM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base path for importing applications under this realm.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Path("application-importers/{formatId}")
|
||||||
|
public Object getApplicationImporter(@PathParam("formatId") String formatId) {
|
||||||
|
ApplicationImporter importer = session.getProvider(ApplicationImporter.class, formatId);
|
||||||
|
return importer.createJaxrsService(realm, auth);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base path for managing applications under this realm.
|
* Base path for managing applications under this realm.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,9 +2,14 @@ package org.keycloak.services.resources.admin;
|
||||||
|
|
||||||
import org.keycloak.Version;
|
import org.keycloak.Version;
|
||||||
import org.keycloak.events.EventListenerProvider;
|
import org.keycloak.events.EventListenerProvider;
|
||||||
|
import org.keycloak.exportimport.ApplicationImporter;
|
||||||
|
import org.keycloak.exportimport.ApplicationImporterFactory;
|
||||||
import org.keycloak.freemarker.Theme;
|
import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeProvider;
|
import org.keycloak.freemarker.ThemeProvider;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.protocol.LoginProtocol;
|
||||||
|
import org.keycloak.protocol.LoginProtocolFactory;
|
||||||
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.social.SocialProvider;
|
import org.keycloak.social.SocialProvider;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
|
@ -37,6 +42,8 @@ public class ServerInfoAdminResource {
|
||||||
setSocialProviders(info);
|
setSocialProviders(info);
|
||||||
setThemes(info);
|
setThemes(info);
|
||||||
setEventListeners(info);
|
setEventListeners(info);
|
||||||
|
setProtocols(info);
|
||||||
|
setApplicationImporters(info);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +76,26 @@ public class ServerInfoAdminResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void setProtocols(ServerInfoRepresentation info) {
|
||||||
|
info.protocols = new LinkedList<String>();
|
||||||
|
for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(LoginProtocol.class)) {
|
||||||
|
info.protocols.add(p.getId());
|
||||||
|
}
|
||||||
|
Collections.sort(info.protocols);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setApplicationImporters(ServerInfoRepresentation info) {
|
||||||
|
info.applicationImporters = new LinkedList<Map<String, String>>();
|
||||||
|
for (ProviderFactory p : session.getKeycloakSessionFactory().getProviderFactories(ApplicationImporter.class)) {
|
||||||
|
ApplicationImporterFactory factory = (ApplicationImporterFactory)p;
|
||||||
|
Map<String, String> data = new HashMap<String, String>();
|
||||||
|
data.put("id", factory.getId());
|
||||||
|
data.put("name", factory.getDisplayName());
|
||||||
|
info.applicationImporters.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class ServerInfoRepresentation {
|
public static class ServerInfoRepresentation {
|
||||||
|
|
||||||
private String version;
|
private String version;
|
||||||
|
@ -76,6 +103,8 @@ public class ServerInfoAdminResource {
|
||||||
private Map<String, List<String>> themes;
|
private Map<String, List<String>> themes;
|
||||||
|
|
||||||
private List<String> socialProviders;
|
private List<String> socialProviders;
|
||||||
|
private List<String> protocols;
|
||||||
|
private List<Map<String, String>> applicationImporters;
|
||||||
|
|
||||||
|
|
||||||
private List<String> eventListeners;
|
private List<String> eventListeners;
|
||||||
|
@ -102,6 +131,14 @@ public class ServerInfoAdminResource {
|
||||||
public List<String> getEventListeners() {
|
public List<String> getEventListeners() {
|
||||||
return eventListeners;
|
return eventListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getProtocols() {
|
||||||
|
return protocols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, String>> getApplicationImporters() {
|
||||||
|
return applicationImporters;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
org.keycloak.protocol.LoginProtocolSpi
|
org.keycloak.protocol.LoginProtocolSpi
|
||||||
|
org.keycloak.exportimport.ApplicationImportSpi
|
|
@ -222,6 +222,18 @@
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>test-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-deploy-plugin</artifactId>
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
|
|
@ -1,15 +1,40 @@
|
||||||
package org.keycloak.testsuite.saml;
|
package org.keycloak.testsuite.saml;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.models.UserSessionModel;
|
||||||
|
import org.keycloak.protocol.oidc.TokenManager;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.services.managers.RealmManager;
|
||||||
|
import org.keycloak.services.resources.admin.AdminRoot;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.rule.WebResource;
|
import org.keycloak.testsuite.rule.WebResource;
|
||||||
import org.keycloak.testsuite.rule.WebRule;
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
import org.openqa.selenium.WebDriver;
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import javax.ws.rs.client.Client;
|
||||||
|
import javax.ws.rs.client.ClientBuilder;
|
||||||
|
import javax.ws.rs.client.ClientRequestContext;
|
||||||
|
import javax.ws.rs.client.ClientRequestFilter;
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.client.WebTarget;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -24,10 +49,12 @@ public class SamlBindingTest {
|
||||||
|
|
||||||
initializeSamlSecuredWar("/saml/simple-post", "/sales-post", "post.war", classLoader);
|
initializeSamlSecuredWar("/saml/simple-post", "/sales-post", "post.war", classLoader);
|
||||||
initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
|
initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
|
||||||
|
initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader);
|
||||||
initializeSamlSecuredWar("/saml/signed-get", "/employee-sig", "employee-sig.war", classLoader);
|
initializeSamlSecuredWar("/saml/signed-get", "/employee-sig", "employee-sig.war", classLoader);
|
||||||
initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
|
initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
|
||||||
initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
|
initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
|
||||||
initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
|
||||||
|
uploadSP();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,5 +140,64 @@ public class SamlBindingTest {
|
||||||
Assert.assertTrue(driver.getPageSource().contains("null"));
|
Assert.assertTrue(driver.getPageSource().contains("null"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String createToken() {
|
||||||
|
KeycloakSession session = keycloakRule.startSession();
|
||||||
|
try {
|
||||||
|
RealmManager manager = new RealmManager(session);
|
||||||
|
|
||||||
|
RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
|
||||||
|
ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
|
TokenManager tm = new TokenManager();
|
||||||
|
UserModel admin = session.users().getUserByUsername("admin", adminRealm);
|
||||||
|
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
|
||||||
|
AccessToken token = tm.createClientAccessToken(tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession);
|
||||||
|
return tm.encodeToken(adminRealm, token);
|
||||||
|
} finally {
|
||||||
|
keycloakRule.stopSession(session, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMetadataPostSignedLoginLogout() throws Exception {
|
||||||
|
|
||||||
|
driver.navigate().to("http://localhost:8081/sales-metadata/");
|
||||||
|
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||||
|
loginPage.login("bburke", "password");
|
||||||
|
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
|
||||||
|
String pageSource = driver.getPageSource();
|
||||||
|
Assert.assertTrue(pageSource.contains("bburke"));
|
||||||
|
driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
|
||||||
|
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void uploadSP() {
|
||||||
|
String token = createToken();
|
||||||
|
final String authHeader = "Bearer " + token;
|
||||||
|
ClientRequestFilter authFilter = new ClientRequestFilter() {
|
||||||
|
@Override
|
||||||
|
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||||
|
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Client client = ClientBuilder.newBuilder().register(authFilter).build();
|
||||||
|
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
|
||||||
|
WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
|
||||||
|
|
||||||
|
|
||||||
|
MultipartFormDataOutput formData = new MultipartFormDataOutput();
|
||||||
|
InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
|
||||||
|
Assert.assertNotNull(is);
|
||||||
|
formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
|
||||||
|
|
||||||
|
WebTarget upload = adminRealms.path("demo/application-importers/saml2-entity-descriptor/upload");
|
||||||
|
System.out.println(upload.getUri());
|
||||||
|
Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
|
||||||
|
Assert.assertEquals(204, response.getStatus());
|
||||||
|
response.close();
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,31 @@
|
||||||
|
<PicketLink xmlns="urn:picketlink:identity-federation:config:2.1">
|
||||||
|
<PicketLinkSP xmlns="urn:picketlink:identity-federation:config:2.1"
|
||||||
|
ServerEnvironment="tomcat" BindingType="POST" SupportsSignatures="true">
|
||||||
|
<IdentityURL>${idp-sig.url::http://localhost:8081/auth/realms/demo/protocol/saml}
|
||||||
|
</IdentityURL>
|
||||||
|
<ServiceURL>${sales-post-sig.url::http://localhost:8081/sales-metadata/}
|
||||||
|
</ServiceURL>
|
||||||
|
<KeyProvider
|
||||||
|
ClassName="org.picketlink.identity.federation.core.impl.KeyStoreKeyManager">
|
||||||
|
<Auth Key="KeyStoreURL" Value="saml/signed-post/WEB-INF/keystore.jks" />
|
||||||
|
<Auth Key="KeyStorePass" Value="store123" />
|
||||||
|
<Auth Key="SigningKeyPass" Value="test123" />
|
||||||
|
<Auth Key="SigningKeyAlias" Value="http://localhost:8080/sales-post-sig/" />
|
||||||
|
<ValidatingAlias Key="localhost" Value="demo" />
|
||||||
|
<ValidatingAlias Key="127.0.0.1" Value="demo" />
|
||||||
|
</KeyProvider>
|
||||||
|
|
||||||
|
</PicketLinkSP>
|
||||||
|
<Handlers xmlns="urn:picketlink:identity-federation:handler:config:2.1">
|
||||||
|
<Handler
|
||||||
|
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2LogOutHandler" />
|
||||||
|
<Handler
|
||||||
|
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2AuthenticationHandler" />
|
||||||
|
<Handler
|
||||||
|
class="org.picketlink.identity.federation.web.handlers.saml2.RolesGenerationHandler" />
|
||||||
|
<Handler
|
||||||
|
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureGenerationHandler" />
|
||||||
|
<Handler
|
||||||
|
class="org.picketlink.identity.federation.web.handlers.saml2.SAML2SignatureValidationHandler" />
|
||||||
|
</Handlers>
|
||||||
|
</PicketLink>
|
38
testsuite/integration/src/test/resources/saml/sp-metadata.xml
Executable file
38
testsuite/integration/src/test/resources/saml/sp-metadata.xml
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<EntitiesDescriptor Name="urn:mace:shibboleth:testshib:two"
|
||||||
|
xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||||
|
>
|
||||||
|
<EntityDescriptor entityID="http://localhost:8081/sales-metadata/">
|
||||||
|
<SPSSODescriptor AuthnRequestsSigned="true"
|
||||||
|
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext">
|
||||||
|
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient
|
||||||
|
</NameIDFormat>
|
||||||
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/sales-metadata/"/>
|
||||||
|
<AssertionConsumerService
|
||||||
|
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/sales-metadata/"
|
||||||
|
index="1" isDefault="true" />
|
||||||
|
<KeyDescriptor use="signing">
|
||||||
|
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
|
||||||
|
<dsig:X509Data>
|
||||||
|
<dsig:X509Certificate>
|
||||||
|
MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==
|
||||||
|
</dsig:X509Certificate>
|
||||||
|
</dsig:X509Data>
|
||||||
|
</dsig:KeyInfo>
|
||||||
|
</KeyDescriptor>
|
||||||
|
</SPSSODescriptor>
|
||||||
|
<Organization>
|
||||||
|
<OrganizationName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||||
|
xml:lang="en">JBoss</OrganizationName>
|
||||||
|
<OrganizationDisplayName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||||
|
xml:lang="en">JBoss by Red Hat</OrganizationDisplayName>
|
||||||
|
<OrganizationURL xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
|
||||||
|
xml:lang="en">http://localhost:8080/sales-metadata/</OrganizationURL>
|
||||||
|
</Organization>
|
||||||
|
<ContactPerson contactType="technical">
|
||||||
|
<GivenName>The</GivenName>
|
||||||
|
<SurName>Admin</SurName>
|
||||||
|
<EmailAddress>admin@mycompany.com</EmailAddress>
|
||||||
|
</ContactPerson>
|
||||||
|
</EntityDescriptor>
|
||||||
|
</EntitiesDescriptor>
|
|
@ -57,9 +57,8 @@
|
||||||
"saml.signature.algorithm": "RSA_SHA256",
|
"saml.signature.algorithm": "RSA_SHA256",
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.authnstatement": "true",
|
"saml.authnstatement": "true",
|
||||||
"privateKey": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB",
|
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||||
"X509Certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -76,9 +75,8 @@
|
||||||
"saml.server.signature": "true",
|
"saml.server.signature": "true",
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.authnstatement": "true",
|
"saml.authnstatement": "true",
|
||||||
"privateKey": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
"saml.signing.private.key": "MIICWwIBAAKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQABAoGADaTtoG/+foOZUiLjRWKL/OmyavK9vjgyFtThNkZY4qHOh0h3og0RdSbgIxAsIpEa1FUwU2W5yvI6mNeJ3ibFgCgcxqPk6GkAC7DWfQfdQ8cS+dCuaFTs8ObIQEvU50YzeNPiiFxRA+MnauCUXaKm/PnDfjd4tPgru7XZvlGh0wECQQDsBbN2cKkBKpr/b5oJiBcBaSZtWiMNuYBDn9x8uORj+Gy/49BUIMHF2EWyxOWz6ocP5YiynNRkPe21Zus7PEr1AkEA5yWQOkxUTIg43s4pxNSeHtL+Ebqcg54lY2xOQK0yufxUVZI8ODctAKmVBMiCKpU3mZQquOaQicuGtocpgxlScQI/YM31zZ5nsxLGf/5GL6KhzPJT0IYn2nk7IoFu7bjn9BjwgcPurpLA52TNMYWQsTqAKwT6DEhG1NaRqNWNpb4VAkBehObAYBwMm5udyHIeEc+CzUalm0iLLa0eRdiN7AUVNpCJ2V2Uo0NcxPux1AgeP5xXydXafDXYkwhINWcNO9qRAkEA58ckAC5loUGwU5dLaugsGH/a2Q8Ac8bmPglwfCstYDpl8Gp/eimb1eKyvDEELOhyImAv4/uZV9wN85V0xZXWsw==",
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVG8a7xGN6ZIkDbeecySygcDfsypjUMNPE4QJjis8B316CvsZQ0hcTTLUyiRpHlHZys2k3xEhHBHymFC1AONcvzZzpb40tAhLHO1qtAnut00khjAdjR3muLVdGkM/zMC7G5s9iIwBVhwOQhy+VsGnCH91EzkjZ4SVEr55KJoyQJQIDAQAB",
|
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
||||||
"X509Certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -95,9 +93,8 @@
|
||||||
"saml.server.signature": "true",
|
"saml.server.signature": "true",
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.authnstatement": "true",
|
"saml.authnstatement": "true",
|
||||||
"privateKey": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB",
|
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||||
"X509Certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -116,9 +113,10 @@
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.encrypt": "true",
|
"saml.encrypt": "true",
|
||||||
"saml.authnstatement": "true",
|
"saml.authnstatement": "true",
|
||||||
"privateKey": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
"saml.signing.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQAB",
|
"saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
|
||||||
"X509Certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
"saml.encryption.private.key": "MIICXQIBAAKBgQDb7kwJPkGdU34hicplwfp6/WmNcaLh94TSc7Jyr9Undp5pkyLgb0DE7EIE+6kSs4LsqCb8HDkB0nLD5DXbBJFd8n0WGoKstelvtg6FtVJMnwN7k7yZbfkPECWH9zF70VeOo9vbzrApNRnct8ZhH5fbflRB4JMA9L9R+LbURdoSKQIDAQABAoGBANtbZG9bruoSGp2s5zhzLzd4hczT6Jfk3o9hYjzNb5Z60ymN3Z1omXtQAdEiiNHkRdNxK+EM7TcKBfmoJqcaeTkW8cksVEAW23ip8W9/XsLqmbU2mRrJiKa+KQNDSHqJi1VGyimi4DDApcaqRZcaKDFXg2KDr/Qt5JFD/o9IIIPZAkEA+ZENdBIlpbUfkJh6Ln+bUTss/FZ1FsrcPZWu13rChRMrsmXsfzu9kZUWdUeQ2Dj5AoW2Q7L/cqdGXS7Mm5XhcwJBAOGZq9axJY5YhKrsksvYRLhQbStmGu5LG75suF+rc/44sFq+aQM7+oeRr4VY88Mvz7mk4esdfnk7ae+cCazqJvMCQQCx1L1cZw3yfRSn6S6u8XjQMjWE/WpjulujeoRiwPPY9WcesOgLZZtYIH8nRL6ehEJTnMnahbLmlPFbttxPRUanAkA11MtSIVcKzkhp2KV2ipZrPJWwI18NuVJXb+3WtjypTrGWFZVNNkSjkLnHIeCYlJIGhDd8OL9zAiBXEm6kmgLNAkBWAg0tK2hCjvzsaA505gWQb4X56uKWdb0IzN+fOLB3Qt7+fLqbVQNQoNGzqey6B4MoS1fUKAStqdGTFYPG/+9t",
|
||||||
|
"saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -136,9 +134,8 @@
|
||||||
"saml.client.signature": "true",
|
"saml.client.signature": "true",
|
||||||
"saml.signature.algorithm": "RSA_SHA1",
|
"saml.signature.algorithm": "RSA_SHA1",
|
||||||
"saml.authnstatement": "true",
|
"saml.authnstatement": "true",
|
||||||
"privateKey": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
|
"saml.signing.private.key": "MIICXQIBAAKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABAoGANU1efgc6ojIvwn7Lsf8GAKN9z2D6uS0T3I9nw1k2CtI+xWhgKAUltEANx5lEfBRYIdYclidRpqrk8DYgzASrDYTHXzqVBJfAk1VrAGpqyRq+TNMLUHkXiTiSDOQ6WqhX93UGMmAgQm1RsLa6+fy1BO/B2y85+Yf2OUylsKS6avECQQDslRDiNFdtEjdvyOL20tQ7+W+eKVxVxKAyQ3gFjIIDizELZt+Jq1Wz6XV9NhK1JFtlVugeD1tlW/+K16fEmDYXAkEAzqKoN/JeGb20rfQldAUWdQbb0jrQAYlgoSU/9fYH9YVJT8vnkfhPBTwIw9H9euf1//lRP/jHltHd5ch4230YyQJBAN3rOkoltPiABPZbpuLGgwS7BwOCYrWlWmurtBLoaTCvyVKbrgXybNL1pBrOtR+rufvGWLeRyja65Gs1vY6BBQMCQQCTsNq/MjJj/522f7yNUl2cw4w2lOa7Um+IflFbAcDqkZu2ty0Kvgns2d4B6INeZ5ECpjaWnMA7YkFRzZnkd2NRAkB8lEY56ScnNigoZkkjtEUd2ejdhZPYuS9SKfv9zHwN+I+DE2vVFZz8GPq/iLcMx13PkZaYaJNQ4FtQY/hRLSn5",
|
||||||
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQAB",
|
"saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
||||||
"X509Certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
</build>
|
</build>
|
||||||
<modules>
|
<modules>
|
||||||
<module>integration</module>
|
<module>integration</module>
|
||||||
|
<module>tomcat7</module>
|
||||||
<module>performance</module>
|
<module>performance</module>
|
||||||
<module>tools</module>
|
<module>tools</module>
|
||||||
<module>performance-web</module>
|
<module>performance-web</module>
|
||||||
|
|
513
testsuite/tomcat7/pom.xml
Executable file
513
testsuite/tomcat7/pom.xml
Executable file
|
@ -0,0 +1,513 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<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">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-testsuite-pom</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.1.0-Alpha1-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-testsuite-tomcat7</artifactId>
|
||||||
|
<name>Keycloak Tomcat 7Integration TestSuite</name>
|
||||||
|
<description />
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-dependencies-server-all</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-admin-client</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<version>${slf4j.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>jaxrs-api</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-jaxrs</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-client</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-crypto</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-multipart-provider</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-jackson-provider</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-undertow</artifactId>
|
||||||
|
<version>${resteasy.version.latest}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.zxing</groupId>
|
||||||
|
<artifactId>javase</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk16</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>${keycloak.apache.httpcomponents.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-ldap-federation</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-undertow-adapter</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>federation-properties-example</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.logging</groupId>
|
||||||
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-servlet</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.undertow</groupId>
|
||||||
|
<artifactId>undertow-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-core-asl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-mapper-asl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.jackson</groupId>
|
||||||
|
<artifactId>jackson-xc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest-all</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
|
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-entitymanager</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.icegreen</groupId>
|
||||||
|
<artifactId>greenmail</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.infinispan</groupId>
|
||||||
|
<artifactId>infinispan-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-java</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>xml-apis</groupId>
|
||||||
|
<artifactId>xml-apis</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-chrome-driver</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketbox</groupId>
|
||||||
|
<artifactId>picketbox-ldap</artifactId>
|
||||||
|
<type>test-jar</type>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketbox</groupId>
|
||||||
|
<artifactId>picketbox-ldap</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.picketlink</groupId>
|
||||||
|
<artifactId>picketlink-wildlfy-common</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.wildfly</groupId>
|
||||||
|
<artifactId>wildfly-undertow</artifactId>
|
||||||
|
<version>${wildfly.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-testsuite-integration</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-testsuite-integration</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-catalina</artifactId>
|
||||||
|
<version>7.0.54</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat</groupId>
|
||||||
|
<artifactId>tomcat-util</artifactId>
|
||||||
|
<version>7.0.54</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
|
<artifactId>tomcat-embed-core</artifactId>
|
||||||
|
<version>7.0.54</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>test-jar</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<workingDirectory>${project.basedir}</workingDirectory>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>keycloak-server</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>org.keycloak.testutils.KeycloakServer</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>mail-server</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>org.keycloak.testutils.MailServer</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
<profile>
|
||||||
|
<id>totp</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>org.keycloak.testutils.TotpGenerator</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>jpa</id>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<keycloak.realm.provider>jpa</keycloak.realm.provider>
|
||||||
|
<keycloak.user.provider>jpa</keycloak.user.provider>
|
||||||
|
<keycloak.eventStore.provider>jpa</keycloak.eventStore.provider>
|
||||||
|
<keycloak.userSessions.provider>jpa</keycloak.userSessions.provider>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>mongo</id>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<keycloak.connectionsMongo.host>localhost</keycloak.connectionsMongo.host>
|
||||||
|
<keycloak.connectionsMongo.port>27018</keycloak.connectionsMongo.port>
|
||||||
|
<keycloak.connectionsMongo.db>keycloak</keycloak.connectionsMongo.db>
|
||||||
|
<keycloak.connectionsMongo.clearOnStartup>true</keycloak.connectionsMongo.clearOnStartup>
|
||||||
|
<keycloak.connectionsMongo.bindIp>127.0.0.1</keycloak.connectionsMongo.bindIp>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
|
||||||
|
<!-- Postpone tests to "integration-test" phase, so that we can bootstrap embedded mongo on 27018 before running tests -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>test</id>
|
||||||
|
<phase>integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<keycloak.realm.provider>mongo</keycloak.realm.provider>
|
||||||
|
<keycloak.user.provider>mongo</keycloak.user.provider>
|
||||||
|
<keycloak.audit.provider>mongo</keycloak.audit.provider>
|
||||||
|
<keycloak.userSessions.provider>mongo</keycloak.userSessions.provider>
|
||||||
|
<keycloak.connectionsMongo.host>${keycloak.connectionsMongo.host}</keycloak.connectionsMongo.host>
|
||||||
|
<keycloak.connectionsMongo.port>${keycloak.connectionsMongo.port}</keycloak.connectionsMongo.port>
|
||||||
|
<keycloak.connectionsMongo.db>${keycloak.connectionsMongo.db}</keycloak.connectionsMongo.db>
|
||||||
|
<keycloak.connectionsMongo.clearOnStartup>${keycloak.connectionsMongo.clearOnStartup}</keycloak.connectionsMongo.clearOnStartup>
|
||||||
|
<keycloak.connectionsMongo.bindIp>${keycloak.connectionsMongo.bindIp}</keycloak.connectionsMongo.bindIp>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>default-test</id>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Embedded mongo -->
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.joelittlejohn.embedmongo</groupId>
|
||||||
|
<artifactId>embedmongo-maven-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>start-mongodb</id>
|
||||||
|
<phase>pre-integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>start</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<port>${keycloak.connectionsMongo.port}</port>
|
||||||
|
<logging>file</logging>
|
||||||
|
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||||
|
<bindIp>${keycloak.connectionsMongo.bindIp}</bindIp>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>stop-mongodb</id>
|
||||||
|
<phase>post-integration-test</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>stop</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>infinispan</id>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<keycloak.realm.cache.provider>infinispan</keycloak.realm.cache.provider>
|
||||||
|
<keycloak.user.cache.provider>infinispan</keycloak.user.cache.provider>
|
||||||
|
<keycloak.userSessions.provider>infinispan</keycloak.userSessions.provider>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<!-- MySQL -->
|
||||||
|
<profile>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>keycloak.connectionsJpa.driver</name>
|
||||||
|
<value>com.mysql.jdbc.Driver</value>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<id>mysql</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>${mysql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<!-- PostgreSQL -->
|
||||||
|
<profile>
|
||||||
|
<activation>
|
||||||
|
<property>
|
||||||
|
<name>keycloak.connectionsJpa.driver</name>
|
||||||
|
<value>org.postgresql.Driver</value>
|
||||||
|
</property>
|
||||||
|
</activation>
|
||||||
|
<id>postgresql</id>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>clean-jpa</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.liquibase</groupId>
|
||||||
|
<artifactId>liquibase-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<changeLogFile>META-INF/jpa-changelog-master.xml</changeLogFile>
|
||||||
|
|
||||||
|
<url>${keycloak.connectionsJpa.url}</url>
|
||||||
|
<driver>${keycloak.connectionsJpa.driver}</driver>
|
||||||
|
<username>${keycloak.connectionsJpa.user}</username>
|
||||||
|
<password>${keycloak.connectionsJpa.password}</password>
|
||||||
|
|
||||||
|
<promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>clean-jpa</id>
|
||||||
|
<phase>clean</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>dropAll</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
283
testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
Executable file
283
testsuite/tomcat7/src/test/java/org/keycloak/testsuite/Tomcat7Test.java
Executable file
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2012, Red Hat, Inc., and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.keycloak.testsuite;
|
||||||
|
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.client.CookieStore;
|
||||||
|
import org.apache.http.client.utils.URLEncodedUtils;
|
||||||
|
import org.apache.http.cookie.Cookie;
|
||||||
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||||
|
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.keycloak.OAuth2Constants;
|
||||||
|
import org.keycloak.adapters.HttpClientBuilder;
|
||||||
|
import org.keycloak.protocol.oidc.OpenIDConnectService;
|
||||||
|
import org.keycloak.services.resources.LoginActionsService;
|
||||||
|
import org.keycloak.testsuite.Constants;
|
||||||
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
|
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||||
|
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||||
|
import org.keycloak.testsuite.rule.WebRule;
|
||||||
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
|
|
||||||
|
import javax.ws.rs.client.Entity;
|
||||||
|
import javax.ws.rs.core.Form;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Tomcat7Test {
|
||||||
|
|
||||||
|
@ClassRule
|
||||||
|
public static KeycloakRule keycloakRule = new KeycloakRule();
|
||||||
|
|
||||||
|
public static class BrowserLogin implements Runnable
|
||||||
|
{
|
||||||
|
|
||||||
|
private WebDriver driver;
|
||||||
|
|
||||||
|
public BrowserLogin() {
|
||||||
|
driver = WebRule.createWebDriver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
driver.manage().deleteAllCookies();
|
||||||
|
OAuthClient oauth = new OAuthClient(driver);
|
||||||
|
oauth.doLogin("test-user@localhost", "password");
|
||||||
|
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||||
|
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||||
|
Assert.assertEquals(200, response.getStatusCode());
|
||||||
|
count.incrementAndGet();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AtomicLong count = new AtomicLong(0);
|
||||||
|
|
||||||
|
public static class JaxrsClientLogin implements Runnable
|
||||||
|
{
|
||||||
|
ResteasyClient client;
|
||||||
|
|
||||||
|
private String baseUrl = Constants.AUTH_SERVER_ROOT;
|
||||||
|
|
||||||
|
private String realm = "test";
|
||||||
|
|
||||||
|
private String responseType = OAuth2Constants.CODE;
|
||||||
|
|
||||||
|
private String grantType = "authorization_code";
|
||||||
|
|
||||||
|
private String clientId = "test-app";
|
||||||
|
|
||||||
|
private String redirectUri = "http://localhost:8081/app/auth";
|
||||||
|
|
||||||
|
|
||||||
|
public JaxrsClientLogin() {
|
||||||
|
DefaultHttpClient httpClient = (DefaultHttpClient) new HttpClientBuilder().build();
|
||||||
|
httpClient.setCookieStore(new CookieStore() {
|
||||||
|
@Override
|
||||||
|
public void addCookie(Cookie cookie) {
|
||||||
|
//To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Cookie> getCookies() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearExpired(Date date) {
|
||||||
|
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
//To change body of implemented methods use File | Settings | File Templates.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
|
||||||
|
this.client = new ResteasyClientBuilder().httpEngine(engine).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLoginFormUrl(String state) {
|
||||||
|
UriBuilder b = OpenIDConnectService.loginPageUrl(UriBuilder.fromUri(baseUrl));
|
||||||
|
if (responseType != null) {
|
||||||
|
b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
|
||||||
|
}
|
||||||
|
if (clientId != null) {
|
||||||
|
b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
|
||||||
|
}
|
||||||
|
if (redirectUri != null) {
|
||||||
|
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
|
||||||
|
}
|
||||||
|
if (state != null) {
|
||||||
|
b.queryParam(OAuth2Constants.STATE, state);
|
||||||
|
}
|
||||||
|
return b.build(realm).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProcessLoginUrl(String state) {
|
||||||
|
UriBuilder b = LoginActionsService.processLoginUrl(UriBuilder.fromUri(baseUrl));
|
||||||
|
if (clientId != null) {
|
||||||
|
b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
|
||||||
|
}
|
||||||
|
if (redirectUri != null) {
|
||||||
|
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
|
||||||
|
}
|
||||||
|
if (state != null) {
|
||||||
|
b.queryParam(OAuth2Constants.STATE, state);
|
||||||
|
}
|
||||||
|
return b.build(realm).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Pattern actionParser = Pattern.compile("action=\"([^\"]+)\"");
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
//this.client = new ResteasyClientBuilder().build();
|
||||||
|
String state = "42";
|
||||||
|
String loginFormUrl = getLoginFormUrl(state);
|
||||||
|
String html = client.target(loginFormUrl).request().get(String.class);
|
||||||
|
Matcher matcher = actionParser.matcher(html);
|
||||||
|
matcher.find();
|
||||||
|
String actionUrl = matcher.group(1);
|
||||||
|
if (!actionUrl.startsWith("http")) {
|
||||||
|
actionUrl = UriBuilder.fromUri(actionUrl).scheme("http").host("localhost").port(8081).build().toString();
|
||||||
|
}
|
||||||
|
Form form = new Form();
|
||||||
|
form.param("username", "test-user@localhost");
|
||||||
|
form.param("password", "password");
|
||||||
|
Response response = client.target(actionUrl).request().post(Entity.form(form));
|
||||||
|
URI uri = null;
|
||||||
|
Assert.assertEquals(302, response.getStatus());
|
||||||
|
uri = response.getLocation();
|
||||||
|
for (String header : response.getHeaders().keySet()) {
|
||||||
|
for (Object value : response.getHeaders().get(header)) {
|
||||||
|
System.out.println(header + ": " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
Assert.assertNotNull(uri);
|
||||||
|
String code = getCode(uri);
|
||||||
|
Assert.assertNotNull(code);
|
||||||
|
|
||||||
|
form = new Form();
|
||||||
|
form.param(OAuth2Constants.GRANT_TYPE, grantType)
|
||||||
|
.param(OAuth2Constants.CODE, code)
|
||||||
|
.param(OAuth2Constants.REDIRECT_URI, redirectUri);
|
||||||
|
|
||||||
|
String authorization = BasicAuthHelper.createHeader(clientId, "password");
|
||||||
|
|
||||||
|
String res = client.target(OpenIDConnectService.accessCodeToTokenUrl(UriBuilder.fromUri(baseUrl)).build(realm)).request()
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, authorization)
|
||||||
|
.post(Entity.form(form), String.class);
|
||||||
|
count.incrementAndGet();
|
||||||
|
//client.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode(URI uri) {
|
||||||
|
Map<String, String> m = new HashMap<String, String>();
|
||||||
|
List<NameValuePair> pairs = URLEncodedUtils.parse(uri, "UTF-8");
|
||||||
|
for (NameValuePair p : pairs) {
|
||||||
|
if (p.getName().equals("code")) return p.getValue();
|
||||||
|
m.put(p.getName(), p.getValue());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void perfJaxrsClientLogin()
|
||||||
|
{
|
||||||
|
long ITERATIONS = 3;
|
||||||
|
JaxrsClientLogin login = new JaxrsClientLogin();
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
//System.out.println("*************************");
|
||||||
|
login.run();
|
||||||
|
}
|
||||||
|
long end = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("took: " + end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void perfBrowserLogin()
|
||||||
|
{
|
||||||
|
long ITERATIONS = 3;
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
BrowserLogin login = new BrowserLogin();
|
||||||
|
for (int i = 0; i < ITERATIONS; i++) {
|
||||||
|
//System.out.println("----------------------------------");
|
||||||
|
login.run();
|
||||||
|
}
|
||||||
|
long end = System.currentTimeMillis() - start;
|
||||||
|
System.out.println("took: " + end);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void multiThread() throws Exception {
|
||||||
|
int num_threads = 20;
|
||||||
|
Thread[] threads = new Thread[num_threads];
|
||||||
|
for (int i = 0; i < num_threads; i++) {
|
||||||
|
threads[i] = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
perfJaxrsClientLogin();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
for (int i = 0; i < num_threads; i++) {
|
||||||
|
threads[i].start();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < num_threads; i++) {
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
long end = System.currentTimeMillis() - start;
|
||||||
|
System.out.println(count.toString() + " took: " + end);
|
||||||
|
System.out.println(count.floatValue() / ((float)end) * 1000+ " logins/s");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.keycloak.testsuite.tomcat7;
|
||||||
|
|
||||||
|
import org.apache.catalina.Context;
|
||||||
|
import org.apache.catalina.LifecycleException;
|
||||||
|
import org.apache.catalina.startup.Tomcat;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class TomcatAdapterTest {
|
||||||
|
public void startServer() throws LifecycleException {
|
||||||
|
Tomcat tomcat = new Tomcat();
|
||||||
|
tomcat.setPort(8080);
|
||||||
|
//tomcat.addWebapp()
|
||||||
|
File base = new File(System.getProperty("java.io.tmpdir"));
|
||||||
|
Context rootCtx = tomcat.addContext("/app", base.getAbsolutePath());
|
||||||
|
//Tomcat.addServlet(rootCtx, "dateServlet", new DatePrintServlet());
|
||||||
|
rootCtx.addServletMapping("/date", "dateServlet");
|
||||||
|
tomcat.start();
|
||||||
|
tomcat.getServer().await();
|
||||||
|
}}
|
Loading…
Reference in a new issue