Compare commits
	
		
			11 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 59374220c1 | |||
| c9fdae715a | |||
| 6fec8d1d64 | |||
| 1471893c2f | |||
| 5b634a1141 | |||
| 127579d0a4 | |||
| 5ab080d7a0 | |||
| 306b196f45 | |||
| 13fe5de466 | |||
| 393ccc0255 | |||
| 4d17cee46c | 
							
								
								
									
										23
									
								
								.env.dist
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.env.dist
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | TRACING_PROVIDER=jaeger | ||||||
|  | TRACING_PROVIDERS_JAEGER_SAMPLING_SERVER_URL=http://jaeger:5778/sampling | ||||||
|  | TRACING_PROVIDERS_JAEGER_LOCAL_AGENT_ADDRESS=jaeger:6831 | ||||||
|  | TRACING_PROVIDERS_JAEGER_SAMPLING_TYPE=const | ||||||
|  | TRACING_PROVIDERS_JAEGER_SAMPLING_VALUE=1 | ||||||
|  | LOG_LEAK_SENSITIVE_VALUES=true | ||||||
|  | URLS_SELF_ISSUER=http://127.0.0.1:4444 | ||||||
|  |  | ||||||
|  | #URLS_CONSENT=http://hydra-login-consent-node.service.consul:3000/consent | ||||||
|  | #URLS_LOGIN=http://hydra-login-consent-node.service.consul:3000/login | ||||||
|  | #URLS_LOGOUT=http://hydra-login-consent-node.service.consul:3000/logout | ||||||
|  |  | ||||||
|  | URLS_CONSENT=http://127.0.0.1:3000/consent | ||||||
|  | URLS_LOGIN=http://127.0.0.1:3000/login | ||||||
|  | URLS_LOGOUT=http://127.0.0.1:3000/logout | ||||||
|  |  | ||||||
|  | STRATEGIES_ACCESS_TOKEN=jwt | ||||||
|  | SECRETS_SYSTEM=dUjs9EV7BuyXUcckKBVrYOdacsggIkna | ||||||
|  | OIDC_SUBJECT_IDENTIFIERS_SUPPORTED_TYPES=public | ||||||
|  | OIDC_SUBJECT_IDENTIFIERS_PAIRWISE_SALT=dUjs9EV7BuyXUcckKBVrYOdacsggIkna | ||||||
|  | SERVE_COOKIES_SAME_SITE_MODE=None | ||||||
|  | SERVE_COOKIES_SAME_SITE_LEGACY_WORKAROUND=true | ||||||
|  | DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4 | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | .env | ||||||
							
								
								
									
										49
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  |  | ||||||
|  | .PHONY: help | ||||||
|  | .DEFAULT_GOAL := help | ||||||
|  |  | ||||||
|  | # Uppercase vars for internal use. | ||||||
|  | UC = $(shell echo '$1' | tr '[:lower:]' '[:upper:]') | ||||||
|  | LOG_ERROR = @printf "\n>> \e[0;31m$1\e[0;00m\n\n" | ||||||
|  | LOG_WARN = @printf "\n>> \e[0;33m$1\e[0;00m\n\n" | ||||||
|  | LOG_INFO = @printf "\n>> \e[0;34m$1\e[0;00m\n\n" | ||||||
|  | LOG_SUCCESS = @printf "\n>> \e[0;36m$1\e[0;00m\n\n" | ||||||
|  | LOG_SUBLINE = @printf "   \e[0;34m$1\e[0;00m\n\n" | ||||||
|  | HYDRA_COMMAND = docker-compose -p kraken -f docker-compose.yml exec hydra | ||||||
|  |  | ||||||
|  | help: | ||||||
|  | 	@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-10s\033[0m %s\n", $$1, $$2}' | ||||||
|  |  | ||||||
|  | up: ## Docker: start compose stack | ||||||
|  | 	$(call LOG_INFO,Up (daemon)) | ||||||
|  | 	docker-compose -p kraken up -d | ||||||
|  |  | ||||||
|  | stop: ## Docker: stop compose stack | ||||||
|  | 	$(call LOG_INFO,Stop docker stack) | ||||||
|  | 	docker-compose -p kraken stop | ||||||
|  |  | ||||||
|  | ps: ## Docker: show containers | ||||||
|  | 	$(call LOG_INFO, Docker containers) | ||||||
|  | 	docker-compose  -p kraken ps | ||||||
|  |  | ||||||
|  | logs: ## Docker: show logs | ||||||
|  | 	docker-compose -p kraken logs -f | ||||||
|  |  | ||||||
|  | generate_keys: ## Generowanie kluczy klienckich | ||||||
|  | 	${HYDRA_COMMAND} hydra clients create \ | ||||||
|  |     --endpoint http://127.0.0.1:4445 \ | ||||||
|  |     --id auth-code-client \ | ||||||
|  |     --secret secret \ | ||||||
|  |     --grant-types authorization_code,refresh_token \ | ||||||
|  |     --response-types code,id_token \ | ||||||
|  |     --scope openid,offline \ | ||||||
|  |     --callbacks http://127.0.0.1:5555/callback | ||||||
|  |  | ||||||
|  |  | ||||||
|  | token_flow: ## Generowanie kluczy klienckich | ||||||
|  | 	${HYDRA_COMMAND} hydra token user \ | ||||||
|  |     --client-id auth-code-client \ | ||||||
|  |     --client-secret secret \ | ||||||
|  |     --endpoint http://127.0.0.1:4444/ \ | ||||||
|  |     --port 5555 \ | ||||||
|  |     --scope openid,offline | ||||||
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,23 +1,43 @@ | |||||||
| # KrakenD api gateway playground | # KrakenD api gateway playground | ||||||
|  |  | ||||||
| Poszczególne etapy pracy i poznawania krakend w osobnych brancz'ach. | ## etap2 (JWT) | ||||||
|  |  | ||||||
| Całość oparta do docker. | Tutaj już będzie deko więcej roboty. Backend z etapu1, czyli prosty nie zabezpieczony serwer REST. | ||||||
|  |  | ||||||
| - etap1 (podstawka) | Do naszej infrastruktury dodajemy usługę [Hydra](https://www.ory.sh/hydra/docs/), która jest dostawcą protokołu **OAuth2** oraz **OpenID** aby zabezpieczyć nasze api za pomocą [JWT](https://jwt.io/). | ||||||
|  |  | ||||||
| Proste zmokowane api oraz krakend config-watcher (restertujący usługę po zmianie pliku konfiguracyjnego). Fajny patent wykorzystujący [Reflex](https://github.com/cespare/reflex). | W poprzednim przykładzie (etap1) KrakenD posłóżył nam do sekwencji zapytań do api i jednej odpowiedzi | ||||||
|  | W tym etapie wprowadzimy nowy request zabezpieczony tokenem JWT: | ||||||
|  |  | ||||||
| Sekwencyjne proxy w KrakenD: |  | ||||||
|  |  | ||||||
| ```mermaid | ```mermaid | ||||||
| sequenceDiagram | sequenceDiagram | ||||||
|     Użytkownik->>KrakenD: /sequential/{id} |     Użytkownik->>KrakenD: /jwt_access <br/>[Authorizaion: Bearer token] | ||||||
|     KrakenD->>Backend: /users/{id}.json |     KrakenD->>DEX: dex/keys | ||||||
|  |     DEX-->>KrakenD: jwk | ||||||
|  |     KrakenD-->>KrakenD: validator <br/>[issuer] | ||||||
|  |     KrakenD->>Backend: /users/1.json | ||||||
|     Backend-->>KrakenD: response_0 |     Backend-->>KrakenD: response_0 | ||||||
|     KrakenD->>Backend: /projects/{response_0.user_id}.json |  | ||||||
|     Backend-->>KrakenD: response_1 |  | ||||||
|     KrakenD-->>KrakenD: merge response[]  |  | ||||||
|     KrakenD->>+Użytkownik: Response |     KrakenD->>+Użytkownik: Response | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | Dodatkowy scope `groups` | ||||||
|  |  | ||||||
|  | ```mermaid | ||||||
|  | sequenceDiagram | ||||||
|  |     Użytkownik->>KrakenD: /jwt_access_admin <br/>[Authorizaion: Bearer token] | ||||||
|  |     KrakenD->>DEX: dex/keys | ||||||
|  |     DEX-->>KrakenD: jwk | ||||||
|  |     KrakenD-->>KrakenD: validator <br/>[issuer, groups: admins] | ||||||
|  |     KrakenD->>Backend: /users/1.json | ||||||
|  |     Backend-->>KrakenD: response_0 | ||||||
|  |     KrakenD->>+Użytkownik: Response | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Request: | ||||||
|  |  | ||||||
|  | http://127.0.0.1:5556/dex/auth?client_id=example-app&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=openid+profile+email+offline_access&state=I+wish+to+wash+my+irish+wristwatch | ||||||
|  |  | ||||||
|  | Request (dodatkowy scope `groups` dający access to strony admina): | ||||||
|  |  | ||||||
|  | http://127.0.0.1:5556/dex/auth?client_id=example-app&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=groups+openid+profile+email+offline_access&state=I+wish+to+wash+my+irish+wristwatch | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										109
									
								
								dex/config-dev.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								dex/config-dev.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  | # The base path of dex and the external name of the OpenID Connect service. | ||||||
|  | # This is the canonical URL that all clients MUST use to refer to dex. If a | ||||||
|  | # path is provided, dex's HTTP service will listen at a non-root URL. | ||||||
|  | issuer: http://127.0.0.1:5556/dex | ||||||
|  |  | ||||||
|  | # The storage configuration determines where dex stores its state. Supported | ||||||
|  | # options include SQL flavors and Kubernetes third party resources. | ||||||
|  | # | ||||||
|  | # See the storage document at Documentation/storage.md for further information. | ||||||
|  | storage: | ||||||
|  |   type: postgres | ||||||
|  |   config: | ||||||
|  |     host: postgresd | ||||||
|  |     port: 5432 | ||||||
|  |     database: dex | ||||||
|  |     user: dex | ||||||
|  |     password: postgres | ||||||
|  |     ssl: | ||||||
|  |       mode: disable | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Configuration for the HTTP endpoints. | ||||||
|  | web: | ||||||
|  |   http: 0.0.0.0:5556 | ||||||
|  |   # Uncomment for HTTPS options. | ||||||
|  |   # https: 127.0.0.1:5554 | ||||||
|  |   # tlsCert: /etc/dex/tls.crt | ||||||
|  |   # tlsKey: /etc/dex/tls.key | ||||||
|  |  | ||||||
|  | # Configuration for telemetry | ||||||
|  | telemetry: | ||||||
|  |   http: 0.0.0.0:5558 | ||||||
|  |  | ||||||
|  | # Uncomment this block to enable the gRPC API. This values MUST be different | ||||||
|  | # from the HTTP endpoints. | ||||||
|  | # grpc: | ||||||
|  | #   addr: 127.0.0.1:5557 | ||||||
|  | #  tlsCert: examples/grpc-client/server.crt | ||||||
|  | #  tlsKey: examples/grpc-client/server.key | ||||||
|  | #  tlsClientCA: /etc/dex/client.crt | ||||||
|  |  | ||||||
|  | # Uncomment this block to enable configuration for the expiration time durations. | ||||||
|  | # expiry: | ||||||
|  | #   deviceRequests: "5m" | ||||||
|  | #   signingKeys: "6h" | ||||||
|  | #   idTokens: "24h" | ||||||
|  |  | ||||||
|  | # Options for controlling the logger. | ||||||
|  | # logger: | ||||||
|  | #   level: "debug" | ||||||
|  | #   format: "text" # can also be "json" | ||||||
|  |  | ||||||
|  | # Default values shown below | ||||||
|  | # oauth2: | ||||||
|  |     # use ["code", "token", "id_token"] to enable implicit flow for web-only clients | ||||||
|  | #   responseTypes: [ "code" ] # also allowed are "token" and "id_token" | ||||||
|  |     # By default, Dex will ask for approval to share data with application | ||||||
|  |     # (approval for sharing data from connected IdP to Dex is separate process on IdP) | ||||||
|  | #   skipApprovalScreen: false | ||||||
|  |     # If only one authentication method is enabled, the default behavior is to | ||||||
|  |     # go directly to it. For connected IdPs, this redirects the browser away | ||||||
|  |     # from application to upstream provider such as the Google login page | ||||||
|  | #   alwaysShowLoginScreen: false | ||||||
|  |     # Uncommend the passwordConnector to use a specific connector for password grants | ||||||
|  | #   passwordConnector: local | ||||||
|  |  | ||||||
|  | # Instead of reading from an external storage, use this list of clients. | ||||||
|  | # | ||||||
|  | # If this option isn't chosen clients may be added through the gRPC API. | ||||||
|  | staticClients: | ||||||
|  | - id: example-app | ||||||
|  |   redirectURIs: | ||||||
|  |   - 'http://127.0.0.1:5555/callback' | ||||||
|  |   name: 'Example App' | ||||||
|  |   secret: ZXhhbXBsZS1hcHAtc2VjcmV0 | ||||||
|  | #  - id: example-device-client | ||||||
|  | #    redirectURIs: | ||||||
|  | #      - /device/callback | ||||||
|  | #    name: 'Static Client for Device Flow' | ||||||
|  | #    public: true | ||||||
|  | connectors: | ||||||
|  | - type: mockCallback | ||||||
|  |   id: mock | ||||||
|  |   name: Example | ||||||
|  | # - type: google | ||||||
|  | #   id: google | ||||||
|  | #   name: Google | ||||||
|  | #   config: | ||||||
|  | #     issuer: https://accounts.google.com | ||||||
|  | #     # Connector config values starting with a "$" will read from the environment. | ||||||
|  | #     clientID: $GOOGLE_CLIENT_ID | ||||||
|  | #     clientSecret: $GOOGLE_CLIENT_SECRET | ||||||
|  | #     redirectURI: http://127.0.0.1:5556/dex/callback | ||||||
|  | #     hostedDomains: | ||||||
|  | #     - $GOOGLE_HOSTED_DOMAIN | ||||||
|  |  | ||||||
|  | # Let dex keep a list of passwords which can be used to login to dex. | ||||||
|  | enablePasswordDB: true | ||||||
|  |  | ||||||
|  | # A static list of passwords to login the end user. By identifying here, dex | ||||||
|  | # won't look in its underlying storage for passwords. | ||||||
|  | # | ||||||
|  | # If this option isn't chosen users may be added through the gRPC API. | ||||||
|  | staticPasswords: | ||||||
|  | - email: "admin@example.com" | ||||||
|  |   # bcrypt hash of the string "password" | ||||||
|  |   hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" | ||||||
|  |   username: "admin" | ||||||
|  |   userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" | ||||||
							
								
								
									
										55
									
								
								dex/config-ldap.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								dex/config-ldap.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | issuer: http://127.0.0.1:5556/dex | ||||||
|  |  | ||||||
|  | storage: | ||||||
|  |   type: postgres | ||||||
|  |   config: | ||||||
|  |     host: postgresd | ||||||
|  |     port: 5432 | ||||||
|  |     database: dex | ||||||
|  |     user: dex | ||||||
|  |     password: postgres | ||||||
|  |     ssl: | ||||||
|  |       mode: disable | ||||||
|  |  | ||||||
|  | connectors: | ||||||
|  | - type: ldap | ||||||
|  |   name: OpenLDAP | ||||||
|  |   id: ldap | ||||||
|  |   config: | ||||||
|  |     host: ldap:389 | ||||||
|  |  | ||||||
|  |     insecureNoSSL: true | ||||||
|  |  | ||||||
|  |     bindDN: cn=admin,dc=example,dc=org | ||||||
|  |     bindPW: admin | ||||||
|  |  | ||||||
|  |     usernamePrompt: Email Address | ||||||
|  |  | ||||||
|  |     userSearch: | ||||||
|  |       baseDN: ou=People,dc=example,dc=org | ||||||
|  |       filter: "(objectClass=person)" | ||||||
|  |       username: mail | ||||||
|  |       idAttr: DN | ||||||
|  |       emailAttr: mail | ||||||
|  |       nameAttr: cn | ||||||
|  |  | ||||||
|  |     groupSearch: | ||||||
|  |       baseDN: ou=Groups,dc=example,dc=org | ||||||
|  |       filter: "(objectClass=groupOfNames)" | ||||||
|  |  | ||||||
|  |       userMatchers: | ||||||
|  |       - userAttr: DN | ||||||
|  |         groupAttr: member | ||||||
|  |  | ||||||
|  |       nameAttr: cn | ||||||
|  |  | ||||||
|  | web: | ||||||
|  |   http: 0.0.0.0:5556 | ||||||
|  |  | ||||||
|  | staticClients: | ||||||
|  | - id: example-app | ||||||
|  |   redirectURIs: | ||||||
|  |   - 'http://127.0.0.1:5555/callback' | ||||||
|  |   name: 'Example App' | ||||||
|  |   secret: ZXhhbXBsZS1hcHAtc2VjcmV0 | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								dex/dex.db
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										0
									
								
								dex/dex.db
									
									
									
									
									
										Executable file
									
								
							| @@ -14,6 +14,37 @@ services: | |||||||
|     ports: |     ports: | ||||||
|       - "8000:8080" |       - "8000:8080" | ||||||
|    |    | ||||||
|  |   ldap: | ||||||
|  |     image: osixia/openldap:1.4.0 | ||||||
|  |     command: ["--copy-service"] | ||||||
|  |     volumes: | ||||||
|  |     - ./ldap/config-ldap.ldif:/container/service/slapd/assets/config/bootstrap/ldif/custom/config-ldap.ldif | ||||||
|  |     ports: | ||||||
|  |     - 389:389 | ||||||
|  |     - 636:636 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   postgresd: | ||||||
|  |     image: postgres:9.6 | ||||||
|  |     ports: | ||||||
|  |       - "5432:5432" | ||||||
|  |     environment: | ||||||
|  |       - POSTGRES_USER=dex | ||||||
|  |       - POSTGRES_PASSWORD=postgres | ||||||
|  |       - POSTGRES_DB=dex | ||||||
|  |  | ||||||
|  |   dex: | ||||||
|  |     image: quay.io/dexidp/dex:latest | ||||||
|  |     command: ["serve", "/config/config-ldap.yaml"] | ||||||
|  |     volumes: | ||||||
|  |       - ./dex:/config | ||||||
|  |     ports: | ||||||
|  |       - 5556:5556 | ||||||
|  |       - 5558:5558 | ||||||
|  |     depends_on: | ||||||
|  |       - postgresd | ||||||
|  |       - ldap | ||||||
|  |  | ||||||
|   kraken: |   kraken: | ||||||
|     image: devopsfaith/krakend:config-watcher |     image: devopsfaith/krakend:config-watcher | ||||||
|     volumes: |     volumes: | ||||||
|   | |||||||
| @@ -73,6 +73,41 @@ | |||||||
|           "sequential": true |           "sequential": true | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "endpoint": "/jwt_access", | ||||||
|  |       "backend": [ | ||||||
|  |         { | ||||||
|  |           "url_pattern": "/users/1.json" | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       "extra_config": { | ||||||
|  |         "github.com/devopsfaith/krakend-jose/validator": { | ||||||
|  |           "alg": "RS256", | ||||||
|  |           "issuer": "http://127.0.0.1:5556/dex", | ||||||
|  |           "jwk-url": "http://dex:5556/dex/keys", | ||||||
|  |           "disable_jwk_security": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "endpoint": "/jwt_access_admin", | ||||||
|  |       "backend": [ | ||||||
|  |         { | ||||||
|  |           "url_pattern": "/users/1.json" | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       "extra_config": { | ||||||
|  |         "github.com/devopsfaith/krakend-jose/validator": { | ||||||
|  |           "alg": "RS256", | ||||||
|  |           "issuer": "http://127.0.0.1:5556/dex", | ||||||
|  |           "jwk-url": "http://dex:5556/dex/keys", | ||||||
|  |           "roles_key": "groups", | ||||||
|  |           "roles": ["admins"], | ||||||
|  |           "disable_jwk_security": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   ] |   ] | ||||||
| } | } | ||||||
|  |        | ||||||
							
								
								
									
										44
									
								
								ldap/config-ldap.ldif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								ldap/config-ldap.ldif
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | # Already included in default config of Docker image osixia/openldap:1.4.0. | ||||||
|  | # | ||||||
|  | # dn: dc=example,dc=org | ||||||
|  | # objectClass: dcObject | ||||||
|  | # objectClass: organization | ||||||
|  | # o: Example Company | ||||||
|  | # dc: example | ||||||
|  |  | ||||||
|  | dn: ou=People,dc=example,dc=org | ||||||
|  | objectClass: organizationalUnit | ||||||
|  | ou: People | ||||||
|  |  | ||||||
|  | dn: cn=jane,ou=People,dc=example,dc=org | ||||||
|  | objectClass: person | ||||||
|  | objectClass: inetOrgPerson | ||||||
|  | sn: doe | ||||||
|  | cn: jane | ||||||
|  | mail: janedoe@example.com | ||||||
|  | userpassword: foo | ||||||
|  |  | ||||||
|  | dn: cn=john,ou=People,dc=example,dc=org | ||||||
|  | objectClass: person | ||||||
|  | objectClass: inetOrgPerson | ||||||
|  | sn: doe | ||||||
|  | cn: john | ||||||
|  | mail: johndoe@example.com | ||||||
|  | userpassword: bar | ||||||
|  |  | ||||||
|  | # Group definitions. | ||||||
|  |  | ||||||
|  | dn: ou=Groups,dc=example,dc=org | ||||||
|  | objectClass: organizationalUnit | ||||||
|  | ou: Groups | ||||||
|  |  | ||||||
|  | dn: cn=admins,ou=Groups,dc=example,dc=org | ||||||
|  | objectClass: groupOfNames | ||||||
|  | cn: admins | ||||||
|  | member: cn=john,ou=People,dc=example,dc=org | ||||||
|  | member: cn=jane,ou=People,dc=example,dc=org | ||||||
|  |  | ||||||
|  | dn: cn=developers,ou=Groups,dc=example,dc=org | ||||||
|  | objectClass: groupOfNames | ||||||
|  | cn: developers | ||||||
|  | member: cn=jane,ou=People,dc=example,dc=org | ||||||
		Reference in New Issue
	
	Block a user