saml broker defaults and export page
This commit is contained in:
parent
f13f0730db
commit
224066f0fd
9 changed files with 139 additions and 15 deletions
|
@ -188,6 +188,24 @@ module.config([ '$routeProvider', function($routeProvider) {
|
|||
},
|
||||
controller : 'RealmIdentityProviderCtrl'
|
||||
})
|
||||
.when('/realms/:realm/identity-provider-settings/provider/:provider_id/:id/export', {
|
||||
templateUrl : resourceUrl + '/partials/realm-identity-provider-export.html',
|
||||
resolve : {
|
||||
realm : function(RealmLoader) {
|
||||
return RealmLoader();
|
||||
},
|
||||
serverInfo : function(ServerInfoLoader) {
|
||||
return ServerInfoLoader();
|
||||
},
|
||||
identityProvider : function(IdentityProviderLoader) {
|
||||
return IdentityProviderLoader();
|
||||
},
|
||||
providerFactory : function(IdentityProviderFactoryLoader) {
|
||||
return IdentityProviderFactoryLoader();
|
||||
}
|
||||
},
|
||||
controller : 'RealmIdentityProviderExportCtrl'
|
||||
})
|
||||
.when('/realms/:realm/default-roles', {
|
||||
templateUrl : resourceUrl + '/partials/realm-default-roles.html',
|
||||
resolve : {
|
||||
|
|
|
@ -796,7 +796,11 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
|
|||
$scope.identityProvider.config.postBindingResponse = $scope.getBoolean($scope.identityProvider.config.postBindingResponse);
|
||||
$scope.identityProvider.config.wantAuthnRequestsSigned = $scope.getBoolean($scope.identityProvider.config.wantAuthnRequestsSigned);
|
||||
} else {
|
||||
$scope.identityProvider.config.validateSignature = true;
|
||||
$scope.identityProvider.config.postBindingAuthnRequest = true;
|
||||
$scope.identityProvider.config.postBindingResponse = true;
|
||||
$scope.identityProvider.config.wantAuthnRequestsSigned = true;
|
||||
$scope.identityProvider.config.nameIDPolicyFormat = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,6 +813,30 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
|
|||
}
|
||||
});
|
||||
|
||||
module.controller('RealmIdentityProviderExportCtrl', function(realm, identityProvider, $scope, $http, IdentityProviderExport) {
|
||||
$scope.realm = realm;
|
||||
$scope.identityProvider = identityProvider;
|
||||
$scope.download = null;
|
||||
$scope.exported = "";
|
||||
$scope.exportedType = "";
|
||||
|
||||
var url = IdentityProviderExport.url({realm: realm.realm, id: identityProvider.id}) ;
|
||||
$http.get(url).success(function(data, status, headers, config) {
|
||||
$scope.exportedType = headers('Content-Type');
|
||||
$scope.exported = data;
|
||||
});
|
||||
|
||||
$scope.download = function() {
|
||||
var suffix = "txt";
|
||||
if ($scope.exportedType == 'application/xml') {
|
||||
suffix = 'xml';
|
||||
} else if ($scope.exportedType == 'application/json') {
|
||||
suffix = 'json';
|
||||
}
|
||||
saveAs(new Blob([$scope.exported], { type: $scope.exportedType }), 'keycloak.' + suffix);
|
||||
}
|
||||
});
|
||||
|
||||
module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, $route, Dialog, Notifications, TimeUnit) {
|
||||
console.log('RealmTokenDetailCtrl');
|
||||
|
||||
|
|
|
@ -1117,6 +1117,16 @@ module.factory('IdentityProvider', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('IdentityProviderExport', function($resource) {
|
||||
var url = authUrl + '/admin/realms/:realm/identity-provider/:id/export';
|
||||
return {
|
||||
url : function(parameters)
|
||||
{
|
||||
return url.replace(':realm', parameters.realm).replace(':id', parameters.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.factory('IdentityProviderFactory', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/identity-provider/providers/:provider_id', {
|
||||
realm : '@realm',
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="resourceUrl + '/partials/realm-menu.html'"></div>
|
||||
<div id="content-area" class="col-md-9" role="main">
|
||||
|
||||
<data-kc-navigation data-kc-current="social" data-kc-realm="realm.realm" data-kc-social="realm.social"></data-kc-navigation>
|
||||
<div id="content">
|
||||
<ol class="breadcrumb">
|
||||
<li><a href="#/realms/{{realm.realm}}/identity-provider-settings">Identity Providers</a></li>
|
||||
<li class="active"><a href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.id}}">{{identityProvider.name}} Provider</a></li>
|
||||
<li class="active">{{identityProvider.name}} Provider Export</li>
|
||||
</ol>
|
||||
<h2 class="pull-left">{{identityProvider.name}} Provider Export</h2>
|
||||
<form class="form-horizontal" name="realmForm" novalidate>
|
||||
<fieldset class="border-top">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<textarea class="form-control" rows="20" kc-select-action="click">{{exported}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="pull-right form-actions">
|
||||
<a class="btn btn-primary btn-lg" data-ng-click="download()" type="submit">Download</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -47,7 +47,16 @@
|
|||
<div class="form-group clearfix" data-ng-show="!importFile">
|
||||
<label class="col-sm-2 control-label" for="nameIDPolicyFormat">NameID Policy Format</label>
|
||||
<div class="col-sm-4">
|
||||
<input class="form-control" id="nameIDPolicyFormat" type="text" ng-model="identityProvider.config.nameIDPolicyFormat">
|
||||
<select id="nameIDPolicyFormat" ng-model="identityProvider.config.nameIDPolicyFormat">
|
||||
<option value="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">Transient</option>
|
||||
<option value="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">Persistent</option>
|
||||
<option value="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">Email</option>
|
||||
<option value="urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos">Kerberos</option>
|
||||
<option value="urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName">X.509 Subject Name</option>
|
||||
<option value="urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName">Windows Domain Qualified Name</option>
|
||||
<option value="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Unspecified</option>
|
||||
</select>
|
||||
<!-- <input class="form-control" id="nameIDPolicyFormat" type="text" ng-model="identityProvider.config.nameIDPolicyFormat"> -->
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="Specifies the URI reference corresponding to a name identifier format. Defaults to urn:oasis:names:tc:SAML:2.0:nameid-format:persistent." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
|
@ -124,6 +133,7 @@
|
|||
</fieldset>
|
||||
|
||||
<div class="pull-right form-actions">
|
||||
<a class="btn btn-lg btn-primary" href="#/realms/{{realm.realm}}/identity-provider-settings/provider/{{identityProvider.providerId}}/{{identityProvider.id}}/export" data-ng-show="!importFile && !newIdentityProvider">Export</a>
|
||||
<button kc-save data-ng-show="!importFile">Save</button>
|
||||
<button type="submit" data-ng-click="clearFileSelect()" data-ng-show="importFile" class="btn btn-lg btn-default">Cancel</button>
|
||||
<button type="submit" data-ng-click="uploadFile()" data-ng-show="importFile" class="btn btn-lg btn-primary">Import from SAML Metadata</button>
|
||||
|
|
|
@ -167,17 +167,6 @@ public class IdentityBrokerService {
|
|||
return getToken(providerId, false);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{provider_id}/export")
|
||||
public Response export(@PathParam("provider_id") String providerId, @QueryParam("format") String format) {
|
||||
try {
|
||||
IdentityProvider identityProvider = getIdentityProvider(providerId);
|
||||
return identityProvider.export(uriInfo, realmModel, format);
|
||||
} catch (Exception e) {
|
||||
return redirectToErrorPage("Could not export public broker configuration for identity provider [" + providerId + "].", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Response getToken(String providerId, boolean forceRetrieval) {
|
||||
this.event.event(EventType.IDENTITY_PROVIDER_RETRIEVE_TOKEN);
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.keycloak.services.resources.admin;
|
||||
|
||||
import org.jboss.resteasy.annotations.cache.NoCache;
|
||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||
import org.keycloak.broker.provider.IdentityProvider;
|
||||
import org.keycloak.broker.provider.IdentityProviderFactory;
|
||||
import org.keycloak.models.ClientIdentityProviderMappingModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
@ -9,31 +12,42 @@ import org.keycloak.models.ModelDuplicateException;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.services.resources.flows.Flows;
|
||||
import org.keycloak.social.SocialIdentityProvider;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Pedro Igor
|
||||
*/
|
||||
public class IdentityProviderResource {
|
||||
|
||||
private final RealmAuth auth;
|
||||
private final RealmModel realm;
|
||||
private final KeycloakSession session;
|
||||
private final IdentityProviderModel identityProviderModel;
|
||||
|
||||
public IdentityProviderResource(RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel) {
|
||||
public IdentityProviderResource(RealmAuth auth, RealmModel realm, KeycloakSession session, IdentityProviderModel identityProviderModel) {
|
||||
this.realm = realm;
|
||||
this.session = session;
|
||||
this.identityProviderModel = identityProviderModel;
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -46,6 +60,7 @@ public class IdentityProviderResource {
|
|||
@DELETE
|
||||
@NoCache
|
||||
public Response delete() {
|
||||
this.auth.requireManage();
|
||||
removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel);
|
||||
removeClientIdentityProviders(this.realm.getApplications(), this.identityProviderModel);
|
||||
this.realm.removeIdentityProviderById(this.identityProviderModel.getId());
|
||||
|
@ -56,6 +71,7 @@ public class IdentityProviderResource {
|
|||
@Consumes("application/json")
|
||||
public Response update(IdentityProviderRepresentation model) {
|
||||
try {
|
||||
this.auth.requireManage();
|
||||
this.realm.updateIdentityProvider(RepresentationToModel.toModel(model));
|
||||
return Response.noContent().build();
|
||||
} catch (ModelDuplicateException e) {
|
||||
|
@ -63,6 +79,33 @@ public class IdentityProviderResource {
|
|||
}
|
||||
}
|
||||
|
||||
private IdentityProviderFactory getIdentityProviderFactory() {
|
||||
List<ProviderFactory> allProviders = new ArrayList<ProviderFactory>();
|
||||
|
||||
allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(IdentityProvider.class));
|
||||
allProviders.addAll(this.session.getKeycloakSessionFactory().getProviderFactories(SocialIdentityProvider.class));
|
||||
|
||||
for (ProviderFactory providerFactory : allProviders) {
|
||||
if (providerFactory.getId().equals(identityProviderModel.getProviderId())) return (IdentityProviderFactory)providerFactory;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("export")
|
||||
public Response export(@Context UriInfo uriInfo, @QueryParam("format") String format) {
|
||||
try {
|
||||
this.auth.requireView();
|
||||
IdentityProviderFactory factory = getIdentityProviderFactory();
|
||||
return factory.create(identityProviderModel).export(uriInfo, realm, format);
|
||||
} catch (Exception e) {
|
||||
return Flows.errors().error("Could not export public broker configuration for identity provider [" + identityProviderModel.getProviderId() + "].", Response.Status.NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removeClientIdentityProviders(List<? extends ClientModel> clients, IdentityProviderModel identityProvider) {
|
||||
for (ClientModel clientModel : clients) {
|
||||
List<ClientIdentityProviderMappingModel> identityProviders = clientModel.getIdentityProviders();
|
||||
|
|
|
@ -151,7 +151,7 @@ public class IdentityProvidersResource {
|
|||
throw new NotFoundException("Could not find identity provider: " + providerId);
|
||||
}
|
||||
|
||||
IdentityProviderResource identityProviderResource = new IdentityProviderResource(realm, session, identityProviderModel);
|
||||
IdentityProviderResource identityProviderResource = new IdentityProviderResource(this.auth, realm, session, identityProviderModel);
|
||||
ResteasyProviderFactory.getInstance().injectProperties(identityProviderResource);
|
||||
|
||||
return identityProviderResource;
|
||||
|
|
|
@ -157,7 +157,7 @@ public class AccountTest {
|
|||
});
|
||||
}
|
||||
|
||||
//@Test @Ignore
|
||||
@Test @Ignore
|
||||
public void runit() throws Exception {
|
||||
Thread.sleep(10000000);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue