Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions gms/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Groups Management Service (gms)

The ***gms*** service provides RESTful web service interface for group management operations. It handles creation, modification, deletion, and querying of user groups, as well as managing group memberships and permissions.

This service works with a user service that provides user identity information. TBD

## deployment
The `gms` war file can be renamed at deployment time in order to support an alternate service name, including
introducing additional path elements.
See <a href="https://github.com/opencadc/docker-base/tree/master/cadc-tomcat">cadc-tomcat</a> (war-rename.conf).

## configuration
The following runtime configuration must be made available via the `/config` directory.

### catalina.properties
This file contains java system properties to configure the tomcat server and some of the java libraries
used in the service.

See <a href="https://github.com/opencadc/docker-base/tree/master/cadc-tomcat">cadc-tomcat</a> for
system properties related to the deployment environment.

See <a href="https://github.com/opencadc/core/tree/master/cadc-util">cadc-util</a> for common system properties.

### cadc-registry.properties

See <a href="https://github.com/opencadc/reg/tree/master/cadc-registry">cadc-registry</a>.

### gms.properties
TBD. At minimum, the following properties are required:
- Corresponding user service base URL and the name of the user identity attribute.

## API Overview

The GMS service provides the following operations:

### Group Management
- **List all groups** - GET /groups
- **Create group** - PUT /groups
- **Get group** - GET /groups/{groupID}
- **Delete group** - DELETE /groups/{groupID}
- **Modify group** - POST /groups/{groupID}
- **Add/Remove user members** - POST/DELETE /groups/{groupID}/userMembers
- **Add/Remove group members** - POST/DELETE /groups/{groupID}/groupMembers (Is it required to distinguish between user and group members?)

### Group Searching
- **Search by role** - GET /search?id={userID}&idType={idType}&role={role}
- **Search specific membership** - GET /search?id={userID}&idType={idType}&role={role}&groupID={groupID}

### Authentication Methods
The service supports multiple authentication methods:
- **Client certificates** (CC) over HTTPS - `/groups/*` endpoints
- **Anonymous** (AN) access for listing operations

## Group Structure

Groups have the following key components:
- **Owner** - Can modify administrator/member lists and delete the group
- **Administrators** - Can modify administrator and member lists
- **Members** - Are granted access to resources the group is associated with

Both users and other groups can be members or administrators of a group.

## building it
```
gradle clean build
docker build -t gms -f Dockerfile .
```

## running it
```
docker run --rm --user tomcat:tomcat --volume=/path/to/external/config:/config:ro --name gms gms:latest
```

## testing it

### Unit tests
```
gradle clean test
```

### Integration tests
```
gradle clean intTest
```

For local testing against a running instance:
```
~/bin/int-test-localhost.sh
```

## API Documentation

For detailed API specifications including request/response formats, authentication requirements, and error codes, see the OpenAPI specification or the service capabilities endpoint at `/capabilities`.
65 changes: 65 additions & 0 deletions gms/model.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@startuml GMS Domain Model

class Group {
- uri: URI
- description: String
- gid: Integer
- lastModified: Date
- owner: User
- userMembers: Set<User>
- userAdmins: Set<User>
- groupMembers: Set<Group>
- groupAdmins: Set<Group>
}

class User {
- identity: Identity
- firstName: String
- lastName: String
- email: String
}

class Identity {
- type: String
- value: String
}

enum IdentityType {
X500
OPENID
NUMERIC
}

enum Role {
OWNER
ADMIN
MEMBER
}

' Relationships
Group "1" *-- "1" User : owner
Group "1" o-- "0..*" User : userMembers
Group "1" o-- "0..*" User : userAdmins
Group "1" o-- "0..*" Group : groupMembers
Group "1" o-- "0..*" Group : groupAdmins

User "1" *-- "1" Identity : key identity

Identity ..> IdentityType : <<uses>>
Group ..> Role : <<defines>>

note right of Group
A group can contain both
users and other groups as
members or administrators
end note

note left of User
Users are identified by
a configurable identity
(primary key) that the
corresponding user service
provides
end note

@enduml
59 changes: 59 additions & 0 deletions gms/src/main/webapp/openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
## GMS OpenAPI root: path items under ./openapi/; shared parameters/schemas/responses live in ./openapi/components.yaml (avoid `$ref` from fragments back into this file — that can deadlock libopenapi/vacuum).
openapi: 3.0.3
info:
title: CANFAR Group Management System (GMS) API
description: |
This API provides RESTful access to group management operations in the CANFAR Group Management System.

Groups have an owner, a list of administrators, and a list of members. The list of members and
administrators can be composed of groups and users.

**Roles:**
- **owner** - Can modify administrators list and members list. Can delete the group.
- **admin** - Can modify the administrators and members list.
- **member** - Are granted access to the resources the group is associated with.

**Authentication Methods:**
- **CC** - Client certificates over HTTPS
- **JWT** - JWT Bearer token over HTTPS
- **AN** - Anonymous over HTTP

**User Identity:**
Users are identified by their unique userID in the Identity Provider (CANFAR HTTP username).
version: 1.0.0
contact:
url: https://www.canfar.net
tags:
Comment thread
andamian marked this conversation as resolved.
- name: Group Management
description: Operations for managing groups
- name: GMS
description: Operations for searching groups by user role (IVOA GMS 1.0)
- name: Group Membership
description: GMS membership and identity-related queries
- name: VOSI Capabilities
description: VOSI capability and probe operations
- name: Service availability
description: Service availability
- name: POSIX Groups
description: POSIX gid / group name search
servers:
Comment thread
andamian marked this conversation as resolved.
- url: https://ws-cadc.canfar.net/gms
description: Production server

paths:
/capabilities:
$ref: ./openapi/vosi/vosi-capabilities.yaml
/availability:
$ref: ./openapi/paths/availability.yaml
/groups:
$ref: ./openapi/paths/groups.yaml
/groups/{groupID}:
$ref: ./openapi/paths/groups-groupid.yaml
/groups/{groupID}/userMembers/{userID}:
$ref: ./openapi/paths/groups-user-members.yaml
/groups/{groupID}/groupMembers/{groupID2}:
$ref: ./openapi/paths/groups-group-members.yaml
/search:
$ref: ./openapi/gms/gms-search.yaml
/gidmap:
$ref: ./openapi/pm/posix-groupmap.yaml
134 changes: 134 additions & 0 deletions gms/src/main/webapp/openapi/components.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Shared components for the GMS OpenAPI description (referenced from path fragments and the root document).
components:
parameters:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter definition style:

I found one of:

- name: groupID
  in: path
...

or (eg)

- $ref: {defined elsewhere}

to be the most compact. See VOSI.git for examples of params defined in separate files.

Having

groupID:
  name: groupID
...

is either redundant or confusing when the two values differ.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works in service parameters but not in components. In components the first occurrence is a key and the second one is the name. Although appears to be a repetition, that is not necessarily so as we could use a different value such as groupIDKey for example. Would that make the intention more obvious?

groupID:
name: groupID
Comment thread
andamian marked this conversation as resolved.
Outdated
in: path
required: true
description: The name of the group
schema:
type: string

userID:
Comment thread
andamian marked this conversation as resolved.
name: userID
in: path
required: true
description: The unique user identifier (CANFAR HTTP username)
schema:
type: string

group:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this param does not belong here

name: group
in: query
description: |
Identifier of a group (IVOID).

This parameter MAY be repeated to test membership in multiple groups.

If omitted, all group memberships SHALL be returned.
required: false
example:
- ivo://example.org/gms?engineering
schema:
type: array
items:
type: string
example: ivo://example.org/gms?engineering
style: form

responses:
BadRequest:
Comment thread
andamian marked this conversation as resolved.
Outdated
description: The URL or input stream data are malformed

Unauthorized:
description: Credentials were not provided

Forbidden:
description: Not allowed to perform the requested action

InternalServerError:
description: The server encountered an unrecoverable error

ServiceUnavailable:
description: The server is too busy to perform the operation

schemas:
Group:
type: object
Comment thread
andamian marked this conversation as resolved.
description: Representation of a group
required:
- uri
properties:
uri:
type: string
description: Group URI (e.g., ivo://cadc.nrc.ca/gms#GroupName)
example: "ivo://cadc.nrc.ca/gms#Example-group"
owner:
$ref: '#/components/schemas/User'
description:
type: string
description: Group description
example: "Group used for documentation example"
lastModified:
type: string
format: date-time
description: Last modification timestamp
example: "2015-07-24T17:38:18.000"
userMembers:
type: array
description: List of users who are members of this group
items:
$ref: '#/components/schemas/User'
example:
- "member1"
- "member2"
userAdmins:
type: array
description: List of users who are administrators of this group
items:
$ref: '#/components/schemas/User'
example:
- "admin1"
groupMembers:
type: array
description: List of groups that are members of this group
items:
type: object
properties:
uri:
type: string
description: URI of the member group
example: "ivo://cadc.nrc.ca/gms#MemberGroup"
example:
- uri: "ivo://cadc.nrc.ca/gms#MemberGroup"
groupAdmins:
type: array
description: List of groups that are administrators of this group
items:
type: object
properties:
uri:
type: string
description: URI of the admin group
example: "ivo://cadc.nrc.ca/gms#AdminGroup"
example:
- uri: "ivo://cadc.nrc.ca/gms#AdminGroup"
example:
uri: "ivo://cadc.nrc.ca/gms#Example-group"
owner: "exampleuser"
description: "Group used for documentation example"
lastModified: "2015-07-24T17:38:18.000"
userMembers:
- "member1"
- "member2"
userAdmins:
- "admin1"
groupMembers:
- uri: "ivo://cadc.nrc.ca/gms#MemberGroup"
groupAdmins:
- uri: "ivo://cadc.nrc.ca/gms#AdminGroup"

User:
type: string
description: User identifier (CANFAR HTTP username)
example: "exampleuser"
Loading
Loading