Skip to content

Commit

Permalink
feat(jans-config-api): session management endpoint (#2158)
Browse files Browse the repository at this point in the history
* feat(jans-config-api): Session endpoint - wip

* feat(jans-config-api): session endpoint wip

* feat(jans-config-api): session endpoint wip

* feat(jans-config-api): session endpoint wip

* feat(jans-config-api): user session management - wip

* feat(jans-config-api): session management

* feat(jans-config-api): session management

* feat(jans-config-api): session management

* feat(jans-config-api): session management
  • Loading branch information
pujavs committed Aug 18, 2022
1 parent 8b99498 commit 30f6e1a
Show file tree
Hide file tree
Showing 15 changed files with 434 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,8 @@ private ApiAccessConstants() {
public static final String AGAMA_WRITE_ACCESS = "https://jans.io/oauth/config/agama.write";
public static final String AGAMA_DELETE_ACCESS = "https://jans.io/oauth/config/agama.delete";

public static final String JANS_AUTH_SESSION_READ_ACCESS = "https://jans.io/oauth/jans-auth-server/session.readonly";
public static final String JANS_AUTH_SESSION_DELETE_ACCESS = "https://jans.io/oauth/jans-auth-server/session.delete";
public static final String JANS_AUTH_REVOKE_SESSION = "revoke_session";

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ private ApiConstants() {}
public static final String REQUEST_OBJECT = "/request_object";
public static final String UMA = "/uma";
public static final String DYN_REGISTRATION = "/dyn_registration";
public static final String SESSIONID = "/sessionid";
public static final String SESSION = "/session";
public static final String CLIENTS = "/clients";
public static final String OPENID = "/openid";
public static final String SCOPES = "/scopes";
Expand Down Expand Up @@ -76,6 +76,8 @@ private ApiConstants() {}
public static final String USERNAME_PATH = "/{username}";
public static final String CLIENTID_PATH = "/{clientId}";
public static final String CREATORID_PATH = "/{creatorId}";
public static final String SESSIONID_PATH = "/{sessionId}";
public static final String USERDN_PATH = "/{userDn}";
public static final String AGAMA = "/agama";
public static final String QNAME_PATH = "{qname}";
public static final String ENABLED = "enabled";
Expand All @@ -98,6 +100,8 @@ private ApiConstants() {}
public static final String CLIENTID = "clientId";
public static final String CREATOR = "creator";
public static final String CREATORID = "creatorId";
public static final String SESSIONID = "sessionId";
public static final String USERDN = "userDn";


public static final String ALL = "all";
Expand Down
121 changes: 120 additions & 1 deletion jans-config-api/docs/jans-config-api-swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ tags:
- name: Statistics - User
- name: Health - Check
- name: Server Stats
- name: Auth - Session Management
- name: Configuration – User Management
- name: SCIM - Config Management
- name: Organization Configuration
Expand Down Expand Up @@ -2815,6 +2816,57 @@ paths:
$ref: '#/components/schemas/StatsData'
'500':
description: Internal Server Error
/jans-config-api/api/v1/jans-auth-server/session:
get:
summary: Returns current session.
description: Returns current session.
operationId: get-sessions
security:
- oauth2: [https://jans.io/oauth/jans-auth-server/session.readonly revoke_session]
tags:
- Auth - Session Management
responses:
'200':
description: OK
content:
application/json:
schema:
title: Auth session
description: List of auth session.
type: array
items:
$ref: '#/components/schemas/SessionId'
'401':
$ref: '#/components/responses/Unauthorized'
'500':
description: Internal Server Error
/jans-config-api/api/v1/jans-auth-server/session/{userDn}:
parameters:
- name: userDn
in: path
description: User domain name.
required: true
schema:
type: string
post:
summary: Revoke all sessions by userDn.
description: Revoke all sessions by userDn.
operationId: revoke-user-session
security:
- oauth2: [https://jans.io/oauth/jans-auth-server/session.delete]
tags:
- Auth - Session Management
responses:
'200':
description: Ok
'401':
$ref: '#/components/responses/Unauthorized'
'404':
description: Not Found
'500':
description: Internal Server Error

/jans-config-api/mgt/configuser:
get:
Expand Down Expand Up @@ -3698,7 +3750,8 @@ components:
https://jans.io/oauth/config/agama.readonly: View Agama Flow related information
https://jans.io/oauth/config/agama.write: Manage Agama Flow related information
https://jans.io/oauth/config/agama.delete: Delete Agama Flow related information

https://jans.io/oauth/jans-auth-server/session.readonly: View Session related information
https://jans.io/oauth/jans-auth-server/session.delete: Delete Session information

responses:
Found:
Expand Down Expand Up @@ -7471,3 +7524,69 @@ components:
codeError:
type: string
description: Errors in the flow source detected by Agama transpiler
SessionId:
title: Session details
description: Session details
type: object
properties:
dn:
type: string
description: Domain name.
id:
type: string
description: Unique session id
outsideSid:
type: string
description: User session id
lastUsedAt:
description: Timestamp of session used last time.
type: string
format: date
userDn:
description: Session user domain name.
type: string
authenticationTime:
description: Session authentication time.
type: string
format: date
state:
description: Session status
type: string
enum:
- authenticated
- unauthenticated
sessionState:
description: state of session.
type: string
permissionGranted:
type: boolean
description: Boolean flag indicated if permission granted
isJwt:
type: boolean
description: Boolean flag indicated if jwt
jwt:
type: string
description: Jwt
permissionGrantedMap:
description: Map containing permission.
type: object
additionalProperties:
type: boolean
sessionAttributes:
description: Session attributes
type: object
additionalProperties:
type: string
expirationDate:
description: Expiration date.
type: string
format: date
deletable:
type: boolean
description: If permission is deletable
creationDate:
description: Session creation date.
type: string
format: date
6 changes: 3 additions & 3 deletions jans-config-api/profiles/local/test.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#LOCAL
test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/config/acrs.write https://jans.io/oauth/config/attributes.readonly https://jans.io/oauth/config/attributes.write https://jans.io/oauth/config/attributes.delete https://jans.io/oauth/config/cache.readonly https://jans.io/oauth/config/cache.write https://jans.io/oauth/config/openid/clients.readonly https://jans.io/oauth/config/openid/clients.write https://jans.io/oauth/config/openid/clients.delete https://jans.io/oauth/jans-auth-server/config/properties.readonly https://jans.io/oauth/jans-auth-server/config/properties.write https://jans.io/oauth/config/smtp.readonly https://jans.io/oauth/config/smtp.write https://jans.io/oauth/config/smtp.delete https://jans.io/oauth/config/database/couchbase.readonly https://jans.io/oauth/config/database/couchbase.write https://jans.io/oauth/config/database/couchbase.delete https://jans.io/oauth/config/scripts.readonly https://jans.io/oauth/config/scripts.write https://jans.io/oauth/config/scripts.delete https://jans.io/oauth/config/fido2.readonly https://jans.io/oauth/config/fido2.write https://jans.io/oauth/config/jwks.readonly https://jans.io/oauth/config/jwks.write https://jans.io/oauth/config/database/ldap.readonly https://jans.io/oauth/config/database/ldap.write https://jans.io/oauth/config/database/ldap.delete https://jans.io/oauth/config/logging.readonly https://jans.io/oauth/config/logging.write https://jans.io/oauth/config/scopes.readonly https://jans.io/oauth/config/scopes.write https://jans.io/oauth/config/scopes.delete https://jans.io/oauth/config/uma/resources.readonly https://jans.io/oauth/config/uma/resources.write https://jans.io/oauth/config/uma/resources.delete https://jans.io/oauth/config/database/sql.readonly https://jans.io/oauth/config/database/sql.write https://jans.io/oauth/config/database/sql.delete https://jans.io/oauth/config/stats.readonly jans_stat https://jans.io/scim/users.read https://jans.io/scim/users.write https://jans.io/oauth/config/scim/users.read https://jans.io/oauth/config/scim/users.write https://jans.io/scim/config.readonly https://jans.io/scim/config.write https://jans.io/oauth/config/organization.readonly https://jans.io/oauth/config/organization.write https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete https://jans.io/oauth/config/agama.readonly https://jans.io/oauth/config/agama.write https://jans.io/oauth/config/agama.delete
test.scopes=https://jans.io/oauth/config/acrs.readonly https://jans.io/oauth/config/acrs.write https://jans.io/oauth/config/attributes.readonly https://jans.io/oauth/config/attributes.write https://jans.io/oauth/config/attributes.delete https://jans.io/oauth/config/cache.readonly https://jans.io/oauth/config/cache.write https://jans.io/oauth/config/openid/clients.readonly https://jans.io/oauth/config/openid/clients.write https://jans.io/oauth/config/openid/clients.delete https://jans.io/oauth/jans-auth-server/config/properties.readonly https://jans.io/oauth/jans-auth-server/config/properties.write https://jans.io/oauth/config/smtp.readonly https://jans.io/oauth/config/smtp.write https://jans.io/oauth/config/smtp.delete https://jans.io/oauth/config/database/couchbase.readonly https://jans.io/oauth/config/database/couchbase.write https://jans.io/oauth/config/database/couchbase.delete https://jans.io/oauth/config/scripts.readonly https://jans.io/oauth/config/scripts.write https://jans.io/oauth/config/scripts.delete https://jans.io/oauth/config/fido2.readonly https://jans.io/oauth/config/fido2.write https://jans.io/oauth/config/jwks.readonly https://jans.io/oauth/config/jwks.write https://jans.io/oauth/config/database/ldap.readonly https://jans.io/oauth/config/database/ldap.write https://jans.io/oauth/config/database/ldap.delete https://jans.io/oauth/config/logging.readonly https://jans.io/oauth/config/logging.write https://jans.io/oauth/config/scopes.readonly https://jans.io/oauth/config/scopes.write https://jans.io/oauth/config/scopes.delete https://jans.io/oauth/config/uma/resources.readonly https://jans.io/oauth/config/uma/resources.write https://jans.io/oauth/config/uma/resources.delete https://jans.io/oauth/config/database/sql.readonly https://jans.io/oauth/config/database/sql.write https://jans.io/oauth/config/database/sql.delete https://jans.io/oauth/config/stats.readonly jans_stat https://jans.io/scim/users.read https://jans.io/scim/users.write https://jans.io/oauth/config/scim/users.read https://jans.io/oauth/config/scim/users.write https://jans.io/scim/config.readonly https://jans.io/scim/config.write https://jans.io/oauth/config/organization.readonly https://jans.io/oauth/config/organization.write https://jans.io/oauth/config/user.readonly https://jans.io/oauth/config/user.write https://jans.io/oauth/config/user.delete https://jans.io/oauth/config/agama.readonly https://jans.io/oauth/config/agama.write https://jans.io/oauth/config/agama.delete https://jans.io/oauth/jans-auth-server/session.readonly https://jans.io/oauth/jans-auth-server/session.delete revoke_session

# jans.server
token.endpoint=https://jans.server1/jans-auth/restv1/token
token.grant.type=client_credentials
test.client.id=1800.e9131b86-f39f-421c-9dde-b7f90c21a2fe
test.client.secret=zur7eMIXyDTu
test.client.id=1800.f32764fe-81ca-4735-8443-2cb9f714df3b
test.client.secret=UKeuz96lEage
test.issuer=https://jans.server1
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public Set<Class<?>> getClasses() {
classes.add(OrganizationResource.class);
classes.add(SqlConfigurationResource.class);
classes.add(AgamaResource.class);
classes.add(SessionResource.class);

return classes;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Janssen Project software is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2020, Janssen Project
*/

package io.jans.configapi.rest.resource.auth;

import io.jans.as.common.model.session.SessionId;
import io.jans.configapi.core.rest.ProtectedApi;

import io.jans.configapi.service.auth.SessionService;
import io.jans.configapi.util.ApiAccessConstants;
import io.jans.configapi.util.ApiConstants;

import jakarta.inject.Inject;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

import java.util.List;

import org.slf4j.Logger;

@Path(ApiConstants.JANS_AUTH + ApiConstants.SESSION)
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class SessionResource extends ConfigBaseResource {

@Inject
Logger log;

@Inject
SessionService sessionService;

@GET
@ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_READ_ACCESS })
public Response getAllSessions() {
final List<SessionId> sessions = sessionService.getSessions();
logger.debug("sessions:{}", sessions);
return Response.ok(sessions).build();
}

@POST
@ProtectedApi(scopes = { ApiAccessConstants.JANS_AUTH_SESSION_DELETE_ACCESS, ApiAccessConstants.JANS_AUTH_REVOKE_SESSION })
@Path(ApiConstants.USERDN_PATH)
public Response getAppConfiguration(@PathParam(ApiConstants.USERDN) @NotNull String userDn) {
logger.debug("userDn:{}", userDn);
sessionService.revokeSession(userDn);
return Response.ok().build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import io.jans.as.client.service.StatService;
import io.jans.as.client.JwkResponse;
import io.jans.as.client.RevokeSessionResponse;
import io.jans.as.client.RevokeSessionRequest;
import io.jans.as.client.TokenRequest;
import io.jans.as.client.TokenResponse;
import io.jans.as.client.service.IntrospectionService;
Expand Down Expand Up @@ -45,7 +47,6 @@
@ApplicationScoped
public class AuthClientFactory {


private static final String CONTENT_TYPE = "Content-Type";

private static Logger log = LoggerFactory.getLogger(AuthClientFactory.class);
Expand All @@ -55,7 +56,7 @@ public static IntrospectionService getIntrospectionService(String url, boolean f
}

public static IntrospectionResponse getIntrospectionResponse(String url, String header, String token,
boolean followRedirects) {
boolean followRedirects) {
log.debug("Introspect Token - url:{}, header:{}, token:{} ,followRedirects:{} ", url, header, token,
followRedirects);
ResteasyWebTarget target = (ResteasyWebTarget) ClientBuilder.newClient()
Expand All @@ -64,13 +65,14 @@ public static IntrospectionResponse getIntrospectionResponse(String url, String
return proxy.introspectToken(header, token);
}

public static JsonNode getStatResponse(String url, String token, String month, String startMonth, String endMonth, String format) {
public static JsonNode getStatResponse(String url, String token, String month, String startMonth, String endMonth,
String format) {
if (log.isDebugEnabled()) {
log.debug("Stat Response Token - url:{}, token:{}, month:{}, startMonth:{}, endMonth:{}, format:{} ", escapeLog(url), escapeLog(token),
escapeLog(month), escapeLog(startMonth), escapeLog(endMonth), escapeLog(format));
log.debug("Stat Response Token - url:{}, token:{}, month:{}, startMonth:{}, endMonth:{}, format:{} ",
escapeLog(url), escapeLog(token), escapeLog(month), escapeLog(startMonth), escapeLog(endMonth),
escapeLog(format));
}
ResteasyWebTarget webTarget = (ResteasyWebTarget) ClientBuilder.newClient()
.target(url);
ResteasyWebTarget webTarget = (ResteasyWebTarget) ClientBuilder.newClient().target(url);
StatService statService = webTarget.proxy(StatService.class);
return statService.stat(token, month, startMonth, endMonth, format);
}
Expand All @@ -89,7 +91,7 @@ public static JsonNode getHealthCheckResponse(String url) {
}

public static TokenResponse requestAccessToken(final String tokenUrl, final String clientId,
final String clientSecret, final String scope) {
final String clientSecret, final String scope) {
log.debug("Request for Access Token - tokenUrl:{}, clientId:{}, clientSecret:{}, scope:{} ", tokenUrl,
clientId, clientSecret, scope);
Response response = null;
Expand Down Expand Up @@ -140,8 +142,7 @@ private static IntrospectionService createIntrospectionService(String url, boole
ApacheHttpClient43Engine engine = null;
try {
engine = ClientFactoryUtil.createEngine(followRedirects);
ResteasyWebTarget resteasyWebTarget = (ResteasyWebTarget) ClientBuilder
.newClient().target(url);
ResteasyWebTarget resteasyWebTarget = (ResteasyWebTarget) ClientBuilder.newClient().target(url);
return resteasyWebTarget.proxy(IntrospectionService.class);
} finally {
if (engine != null) {
Expand Down Expand Up @@ -189,6 +190,35 @@ public static JSONWebKeySet getJSONWebKeys(String jwksUri) {
return null;
}

public static RevokeSessionResponse revokeSession(String url, String token, String userId) {
log.debug("Request for Access Token - url:{}, token:{}, userId:{} ", url,
token, userId);
Response response = null;
try {
RevokeSessionRequest revokeSessionRequest = new RevokeSessionRequest("uid", "test");

Builder request = getClientBuilder(url);
request.header("Authorization", "Basic " + token);
request.header(CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED);
final MultivaluedHashMap<String, String> multivaluedHashMap = new MultivaluedHashMap<>(
revokeSessionRequest.getParameters());
response = request.post(Entity.form(multivaluedHashMap));
log.trace("Response for Access Token - response:{}", response);
if (response.getStatus() == 200) {
String entity = response.readEntity(String.class);
RevokeSessionResponse revokeSessionResponse = new RevokeSessionResponse();
revokeSessionResponse.setEntity(entity);
revokeSessionResponse.injectDataFromJson(entity);
return revokeSessionResponse;
}
} finally {

if (response != null) {
response.close();
}
}
return null;
}

private static Builder getClientBuilder(String url) {
return ClientBuilder.newClient().target(url).request();
Expand Down
Loading

0 comments on commit 30f6e1a

Please sign in to comment.