mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-06 11:31:00 -05:00
Add 'glauth/' from commit '0735ec933777cb5fd1427c5311dcb6712def476d'
git-subtree-dir: glauth git-subtree-mainline:d6733b47ccgit-subtree-split:0735ec9337
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
---
|
||||
exclude_paths:
|
||||
- CHANGELOG.md
|
||||
- changelog/**
|
||||
- docs/**
|
||||
- pkg/proto/**
|
||||
|
||||
...
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!bin/
|
||||
@@ -0,0 +1,698 @@
|
||||
def main(ctx):
|
||||
before = [
|
||||
testing(ctx),
|
||||
]
|
||||
|
||||
stages = [
|
||||
docker(ctx, 'amd64'),
|
||||
docker(ctx, 'arm64'),
|
||||
docker(ctx, 'arm'),
|
||||
binary(ctx, 'linux'),
|
||||
binary(ctx, 'darwin'),
|
||||
binary(ctx, 'windows'),
|
||||
]
|
||||
|
||||
after = [
|
||||
manifest(ctx),
|
||||
changelog(ctx),
|
||||
readme(ctx),
|
||||
badges(ctx),
|
||||
website(ctx),
|
||||
]
|
||||
|
||||
return before + stages + after
|
||||
|
||||
def testing(ctx):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'testing',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'generate',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make generate',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'vet',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make vet',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'staticcheck',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make staticcheck',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'lint',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make lint',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'build',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make build',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'test',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make test',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'codacy',
|
||||
'image': 'plugins/codacy:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'token': {
|
||||
'from_secret': 'codacy_token',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'temp': {},
|
||||
},
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def docker(ctx, arch):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': arch,
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': arch,
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'generate',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make generate',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'build',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make build',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'dryrun',
|
||||
'image': 'plugins/docker:18.09',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'dry_run': True,
|
||||
'tags': 'linux-%s' % (arch),
|
||||
'dockerfile': 'docker/Dockerfile.linux.%s' % (arch),
|
||||
'repo': ctx.repo.slug,
|
||||
},
|
||||
'when': {
|
||||
'ref': {
|
||||
'include': [
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'docker',
|
||||
'image': 'plugins/docker:18.09',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'username': {
|
||||
'from_secret': 'docker_username',
|
||||
},
|
||||
'password': {
|
||||
'from_secret': 'docker_password',
|
||||
},
|
||||
'auto_tag': True,
|
||||
'auto_tag_suffix': 'linux-%s' % (arch),
|
||||
'dockerfile': 'docker/Dockerfile.linux.%s' % (arch),
|
||||
'repo': ctx.repo.slug,
|
||||
},
|
||||
'when': {
|
||||
'ref': {
|
||||
'exclude': [
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'temp': {},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'testing',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def binary(ctx, name):
|
||||
if ctx.build.event == "tag":
|
||||
settings = {
|
||||
'endpoint': {
|
||||
'from_secret': 's3_endpoint',
|
||||
},
|
||||
'access_key': {
|
||||
'from_secret': 'aws_access_key_id',
|
||||
},
|
||||
'secret_key': {
|
||||
'from_secret': 'aws_secret_access_key',
|
||||
},
|
||||
'bucket': {
|
||||
'from_secret': 's3_bucket',
|
||||
},
|
||||
'path_style': True,
|
||||
'strip_prefix': 'dist/release/',
|
||||
'source': 'dist/release/*',
|
||||
'target': '/ocis/%s/%s' % (ctx.repo.name.replace("ocis-", ""), ctx.build.ref.replace("refs/tags/v", "")),
|
||||
}
|
||||
else:
|
||||
settings = {
|
||||
'endpoint': {
|
||||
'from_secret': 's3_endpoint',
|
||||
},
|
||||
'access_key': {
|
||||
'from_secret': 'aws_access_key_id',
|
||||
},
|
||||
'secret_key': {
|
||||
'from_secret': 'aws_secret_access_key',
|
||||
},
|
||||
'bucket': {
|
||||
'from_secret': 's3_bucket',
|
||||
},
|
||||
'path_style': True,
|
||||
'strip_prefix': 'dist/release/',
|
||||
'source': 'dist/release/*',
|
||||
'target': '/ocis/%s/testing' % (ctx.repo.name.replace("ocis-", "")),
|
||||
}
|
||||
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': name,
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'generate',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make generate',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'build',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make release-%s' % (name),
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'finish',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make release-finish',
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'path': '/srv/app',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'upload',
|
||||
'image': 'plugins/s3:1',
|
||||
'pull': 'always',
|
||||
'settings': settings,
|
||||
'when': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'changelog',
|
||||
'image': 'toolhippie/calens:latest',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'calens --version %s -o dist/CHANGELOG.md' % ctx.build.ref.replace("refs/tags/v", "").split("-")[0],
|
||||
],
|
||||
'when': {
|
||||
'ref': [
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'release',
|
||||
'image': 'plugins/github-release:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'api_key': {
|
||||
'from_secret': 'github_token',
|
||||
},
|
||||
'files': [
|
||||
'dist/release/*',
|
||||
],
|
||||
'title': ctx.build.ref.replace("refs/tags/v", ""),
|
||||
'note': 'dist/CHANGELOG.md',
|
||||
'overwrite': True,
|
||||
'prerelease': len(ctx.build.ref.split("-")) > 1,
|
||||
},
|
||||
'when': {
|
||||
'ref': [
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
'volumes': [
|
||||
{
|
||||
'name': 'gopath',
|
||||
'temp': {},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'testing',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def manifest(ctx):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'manifest',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'execute',
|
||||
'image': 'plugins/manifest:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'username': {
|
||||
'from_secret': 'docker_username',
|
||||
},
|
||||
'password': {
|
||||
'from_secret': 'docker_password',
|
||||
},
|
||||
'spec': 'docker/manifest.tmpl',
|
||||
'auto_tag': True,
|
||||
'ignore_missing': True,
|
||||
},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'amd64',
|
||||
'arm64',
|
||||
'arm',
|
||||
'linux',
|
||||
'darwin',
|
||||
'windows',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def changelog(ctx):
|
||||
repo_slug = ctx.build.source_repo if ctx.build.source_repo else ctx.repo.slug
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'changelog',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'clone': {
|
||||
'disable': True,
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'clone',
|
||||
'image': 'plugins/git-action:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'actions': [
|
||||
'clone',
|
||||
],
|
||||
'remote': 'https://github.com/%s' % (repo_slug),
|
||||
'branch': ctx.build.source if ctx.build.event == 'pull_request' else 'master',
|
||||
'path': '/drone/src',
|
||||
'netrc_machine': 'github.com',
|
||||
'netrc_username': {
|
||||
'from_secret': 'github_username',
|
||||
},
|
||||
'netrc_password': {
|
||||
'from_secret': 'github_token',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'generate',
|
||||
'image': 'webhippie/golang:1.13',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'make changelog',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'diff',
|
||||
'image': 'owncloud/alpine:latest',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'git diff',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'output',
|
||||
'image': 'owncloud/alpine:latest',
|
||||
'pull': 'always',
|
||||
'commands': [
|
||||
'cat CHANGELOG.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'publish',
|
||||
'image': 'plugins/git-action:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'actions': [
|
||||
'commit',
|
||||
'push',
|
||||
],
|
||||
'message': 'Automated changelog update [skip ci]',
|
||||
'branch': 'master',
|
||||
'author_email': 'devops@owncloud.com',
|
||||
'author_name': 'ownClouders',
|
||||
'netrc_machine': 'github.com',
|
||||
'netrc_username': {
|
||||
'from_secret': 'github_username',
|
||||
},
|
||||
'netrc_password': {
|
||||
'from_secret': 'github_token',
|
||||
},
|
||||
},
|
||||
'when': {
|
||||
'ref': {
|
||||
'exclude': [
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'manifest',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def readme(ctx):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'readme',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'execute',
|
||||
'image': 'sheogorath/readme-to-dockerhub:latest',
|
||||
'pull': 'always',
|
||||
'environment': {
|
||||
'DOCKERHUB_USERNAME': {
|
||||
'from_secret': 'docker_username',
|
||||
},
|
||||
'DOCKERHUB_PASSWORD': {
|
||||
'from_secret': 'docker_password',
|
||||
},
|
||||
'DOCKERHUB_REPO_PREFIX': ctx.repo.namespace,
|
||||
'DOCKERHUB_REPO_NAME': ctx.repo.name,
|
||||
'SHORT_DESCRIPTION': 'Docker images for %s' % (ctx.repo.name),
|
||||
'README_PATH': 'README.md',
|
||||
},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'changelog',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def badges(ctx):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'badges',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'execute',
|
||||
'image': 'plugins/webhook:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'urls': {
|
||||
'from_secret': 'microbadger_url',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'readme',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/tags/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
def website(ctx):
|
||||
return {
|
||||
'kind': 'pipeline',
|
||||
'type': 'docker',
|
||||
'name': 'website',
|
||||
'platform': {
|
||||
'os': 'linux',
|
||||
'arch': 'amd64',
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
'name': 'prepare',
|
||||
'image': 'owncloudci/alpine:latest',
|
||||
'commands': [
|
||||
'make docs-copy'
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'test',
|
||||
'image': 'webhippie/hugo:latest',
|
||||
'commands': [
|
||||
'cd hugo',
|
||||
'hugo',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'list',
|
||||
'image': 'owncloudci/alpine:latest',
|
||||
'commands': [
|
||||
'tree hugo/public',
|
||||
],
|
||||
},
|
||||
{
|
||||
'name': 'publish',
|
||||
'image': 'plugins/gh-pages:1',
|
||||
'pull': 'always',
|
||||
'settings': {
|
||||
'username': {
|
||||
'from_secret': 'github_username',
|
||||
},
|
||||
'password': {
|
||||
'from_secret': 'github_token',
|
||||
},
|
||||
'pages_directory': 'docs/',
|
||||
'target_branch': 'docs',
|
||||
},
|
||||
'when': {
|
||||
'ref': {
|
||||
'exclude': [
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'name': 'downstream',
|
||||
'image': 'plugins/downstream',
|
||||
'settings': {
|
||||
'server': 'https://cloud.drone.io/',
|
||||
'token': {
|
||||
'from_secret': 'drone_token',
|
||||
},
|
||||
'repositories': [
|
||||
'owncloud/owncloud.github.io@source',
|
||||
],
|
||||
},
|
||||
'when': {
|
||||
'ref': {
|
||||
'exclude': [
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
'depends_on': [
|
||||
'badges',
|
||||
],
|
||||
'trigger': {
|
||||
'ref': [
|
||||
'refs/heads/master',
|
||||
'refs/pull/**',
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.starlark]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{yml,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{js,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{css,less}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = true
|
||||
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
# Configuration for update-docs - https://github.com/behaviorbot/update-docs
|
||||
|
||||
# Comment to be posted to on PRs that don't update documentation
|
||||
updateDocsComment: >
|
||||
Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would create a [changelog](https://github.com/owncloud/ocis-glauth/blob/master/changelog/README.md) item based on your changes.
|
||||
updateDocsWhiteList:
|
||||
- Tests-only
|
||||
- tests-only
|
||||
- Tests-Only
|
||||
|
||||
updateDocsTargetFiles:
|
||||
- changelog/unreleased/
|
||||
Vendored
+98
@@ -0,0 +1,98 @@
|
||||
---
|
||||
repository:
|
||||
name: ocis-glauth
|
||||
description: ':atom_symbol: GLAuth for OCIS'
|
||||
homepage: https://owncloud.github.io/ocis-glauth/
|
||||
topics: reva, ocis
|
||||
|
||||
private: false
|
||||
has_issues: true
|
||||
has_projects: false
|
||||
has_wiki: false
|
||||
has_downloads: false
|
||||
|
||||
default_branch: master
|
||||
|
||||
allow_squash_merge: true
|
||||
allow_merge_commit: true
|
||||
allow_rebase_merge: true
|
||||
|
||||
labels:
|
||||
- name: bug
|
||||
color: d73a4a
|
||||
description: Something isn't working
|
||||
- name: documentation
|
||||
color: 0075ca
|
||||
description: Improvements or additions to documentation
|
||||
- name: duplicate
|
||||
color: cfd3d7
|
||||
description: This issue or pull request already exists
|
||||
- name: enhancement
|
||||
color: a2eeef
|
||||
description: New feature or request
|
||||
- name: good first issue
|
||||
color: 7057ff
|
||||
description: Good for newcomers
|
||||
- name: help wanted
|
||||
color: 008672
|
||||
description: Extra attention is needed
|
||||
- name: invalid
|
||||
color: e4e669
|
||||
description: This doesn't seem right
|
||||
- name: question
|
||||
color: d876e3
|
||||
description: Further information is requested
|
||||
- name: wontfix
|
||||
color: ffffff
|
||||
description: This will not be worked on
|
||||
- name: effort/trivial
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/0.25d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/0.5d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/1d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/2d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/4d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/5d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
- name: effort/10d
|
||||
color: c2e0c6
|
||||
description: Required effort to finish task
|
||||
|
||||
teams:
|
||||
- name: ci
|
||||
permission: admin
|
||||
- name: employees
|
||||
permission: push
|
||||
|
||||
branches:
|
||||
- name: master
|
||||
protection:
|
||||
required_pull_request_reviews:
|
||||
required_approving_review_count: 1
|
||||
dismiss_stale_reviews: false
|
||||
require_code_owner_reviews: false
|
||||
dismissal_restrictions: {}
|
||||
required_status_checks:
|
||||
strict: true
|
||||
contexts:
|
||||
- continuous-integration/drone/pr
|
||||
enforce_admins: false
|
||||
restrictions:
|
||||
users: []
|
||||
teams:
|
||||
- ci
|
||||
- employees
|
||||
|
||||
...
|
||||
@@ -0,0 +1,7 @@
|
||||
coverage.out
|
||||
|
||||
/bin
|
||||
/dist
|
||||
/hugo
|
||||
ldap.key
|
||||
ldap.crt
|
||||
@@ -0,0 +1,207 @@
|
||||
# Changelog for [unreleased] (UNRELEASED)
|
||||
|
||||
The following sections list the changes in ocis-glauth unreleased.
|
||||
|
||||
[unreleased]: https://github.com/owncloud/ocis-glauth/compare/v0.5.0...master
|
||||
|
||||
## Summary
|
||||
|
||||
* Bugfix - Return invalid credentials when user was not found: [#30](https://github.com/owncloud/ocis-glauth/pull/30)
|
||||
* Bugfix - Query numeric attribute values without quotes: [#28](https://github.com/owncloud/ocis-glauth/issues/28)
|
||||
* Bugfix - Use searchBaseDN if already a user/group name: [#214](https://github.com/owncloud/product/issues/214)
|
||||
* Bugfix - Fix LDAP substring startswith filters: [#31](https://github.com/owncloud/ocis-glauth/pull/31)
|
||||
|
||||
## Details
|
||||
|
||||
* Bugfix - Return invalid credentials when user was not found: [#30](https://github.com/owncloud/ocis-glauth/pull/30)
|
||||
|
||||
We were relying on an error code of the ListAccounts call when the username and password was
|
||||
wrong. But the list will be empty if no user with the given login was found. So we also need to check
|
||||
if the list of accounts is empty.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/30
|
||||
|
||||
|
||||
* Bugfix - Query numeric attribute values without quotes: [#28](https://github.com/owncloud/ocis-glauth/issues/28)
|
||||
|
||||
Some LDAP properties like `uidnumber` and `gidnumber` are numeric. When an OS tries to look up a
|
||||
user it will not only try to lookup the user by username, but also by the `uidnumber`:
|
||||
`(&(objectclass=posixAccount)(uidnumber=20000))`. The accounts backend for glauth was
|
||||
sending that as a string query `uid_number eq '20000'` in the ListAccounts query. This PR
|
||||
changes that to `uid_number eq 20000`. The removed quotes allow the parser in ocis-accounts to
|
||||
identify the numeric literal.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/28
|
||||
https://github.com/owncloud/ocis-glauth/pull/29
|
||||
https://github.com/owncloud/ocis-accounts/pull/68
|
||||
|
||||
|
||||
* Bugfix - Use searchBaseDN if already a user/group name: [#214](https://github.com/owncloud/product/issues/214)
|
||||
|
||||
In case of the searchBaseDN already referencing a user or group, the search query was ignoring
|
||||
the user/group name entirely, because the searchBaseDN is not part of the LDAP filters. We
|
||||
fixed this by including an additional query part if the searchBaseDN contains a CN.
|
||||
|
||||
https://github.com/owncloud/product/issues/214
|
||||
https://github.com/owncloud/ocis-glauth/pull/32
|
||||
|
||||
|
||||
* Bugfix - Fix LDAP substring startswith filters: [#31](https://github.com/owncloud/ocis-glauth/pull/31)
|
||||
|
||||
Filters like `(mail=mar*)` are currentld not parsed correctly, but they are used when
|
||||
searching for recipients. This PR correctly converts them to odata filters like
|
||||
`startswith(mail,'mar')`.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/31
|
||||
|
||||
# Changelog for [0.5.0] (2020-07-23)
|
||||
|
||||
The following sections list the changes in ocis-glauth 0.5.0.
|
||||
|
||||
[0.5.0]: https://github.com/owncloud/ocis-glauth/compare/v0.4.0...v0.5.0
|
||||
|
||||
## Summary
|
||||
|
||||
* Bugfix - Ignore case when comparing objectclass values: [#26](https://github.com/owncloud/ocis-glauth/pull/26)
|
||||
* Bugfix - Build docker images with alpine:latest instead of alpine:edge: [#24](https://github.com/owncloud/ocis-glauth/pull/24)
|
||||
* Enhancement - Handle ownCloudUUID attribute: [#27](https://github.com/owncloud/ocis-glauth/pull/27)
|
||||
* Enhancement - Implement group queries: [#22](https://github.com/owncloud/ocis-glauth/issues/22)
|
||||
|
||||
## Details
|
||||
|
||||
* Bugfix - Ignore case when comparing objectclass values: [#26](https://github.com/owncloud/ocis-glauth/pull/26)
|
||||
|
||||
The LDAP equality comparison is specified as case insensitive. We fixed the comparison for
|
||||
objectclass properties.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/26
|
||||
|
||||
|
||||
* Bugfix - Build docker images with alpine:latest instead of alpine:edge: [#24](https://github.com/owncloud/ocis-glauth/pull/24)
|
||||
|
||||
ARM builds were failing when built on alpine:edge, so we switched to alpine:latest instead.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/24
|
||||
|
||||
|
||||
* Enhancement - Handle ownCloudUUID attribute: [#27](https://github.com/owncloud/ocis-glauth/pull/27)
|
||||
|
||||
Clients can now query an accounts immutable id by using the [new `ownCloudUUID`
|
||||
attribute](https://github.com/butonic/owncloud-ldap-schema/blob/master/owncloud.schema#L28-L34).
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/27
|
||||
|
||||
|
||||
* Enhancement - Implement group queries: [#22](https://github.com/owncloud/ocis-glauth/issues/22)
|
||||
|
||||
Refactored the handler and implemented group queries.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/22
|
||||
https://github.com/owncloud/ocis-glauth/pull/23
|
||||
|
||||
# Changelog for [0.4.0] (2020-03-18)
|
||||
|
||||
The following sections list the changes in ocis-glauth 0.4.0.
|
||||
|
||||
[0.4.0]: https://github.com/owncloud/ocis-glauth/compare/v0.2.0...v0.4.0
|
||||
|
||||
## Summary
|
||||
|
||||
* Enhancement - Configuration: [#11](https://github.com/owncloud/ocis-glauth/pull/11)
|
||||
* Enhancement - Improve default settings: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
* Enhancement - Generate temporary ldap certificates if LDAPS is enabled: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
* Enhancement - Provide additional tls-endpoint: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
|
||||
## Details
|
||||
|
||||
* Enhancement - Configuration: [#11](https://github.com/owncloud/ocis-glauth/pull/11)
|
||||
|
||||
Extensions should be responsible of configuring themselves. We use Viper for config loading
|
||||
from default paths. Environment variables **WILL** take precedence over config files.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/11
|
||||
|
||||
|
||||
* Enhancement - Improve default settings: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
|
||||
This helps achieve zero-config in single-binary.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
|
||||
|
||||
* Enhancement - Generate temporary ldap certificates if LDAPS is enabled: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
|
||||
This change helps to achieve zero-configuration in single-binary mode.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
|
||||
|
||||
* Enhancement - Provide additional tls-endpoint: [#12](https://github.com/owncloud/ocis-glauth/pull/12)
|
||||
|
||||
Ocis-glauth is now able to concurrently serve a encrypted and an unencrypted ldap-port.
|
||||
Please note that only SSL (no StarTLS) is supported at the moment.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
|
||||
# Changelog for [0.2.0] (2020-03-17)
|
||||
|
||||
The following sections list the changes in ocis-glauth 0.2.0.
|
||||
|
||||
[0.2.0]: https://github.com/owncloud/ocis-glauth/compare/v0.3.0...v0.2.0
|
||||
|
||||
## Summary
|
||||
|
||||
* Change - Default to config based user backend: [#6](https://github.com/owncloud/ocis-glauth/pull/6)
|
||||
|
||||
## Details
|
||||
|
||||
* Change - Default to config based user backend: [#6](https://github.com/owncloud/ocis-glauth/pull/6)
|
||||
|
||||
We changed the default configuration to use the config file backend instead of the ownCloud
|
||||
backend.
|
||||
|
||||
The config backend currently only has two hard coded users: demo and admin. To switch back to the
|
||||
ownCloud backend use `GLAUTH_BACKEND_DATASTORE=owncloud`
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/6
|
||||
|
||||
# Changelog for [0.3.0] (2020-03-17)
|
||||
|
||||
The following sections list the changes in ocis-glauth 0.3.0.
|
||||
|
||||
[0.3.0]: https://github.com/owncloud/ocis-glauth/compare/v0.1.0...v0.3.0
|
||||
|
||||
## Summary
|
||||
|
||||
* Change - Use physicist demo users: [#5](https://github.com/owncloud/ocis-glauth/issues/5)
|
||||
|
||||
## Details
|
||||
|
||||
* Change - Use physicist demo users: [#5](https://github.com/owncloud/ocis-glauth/issues/5)
|
||||
|
||||
Demo users like admin, demo and test don't allow you to tell a story. Which is why we changed the
|
||||
set of hard coded demo users to `einstein`, `marie` and `feynman`. You should know who they are.
|
||||
This also changes the ldap domain from `dc=owncloud,dc=com` to `dc=example,dc=org` because
|
||||
that is what these users use as their email domain. There are also `konnectd` and `reva` for
|
||||
technical purposes, eg. to allow konnectd and reva to bind to glauth.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/5
|
||||
|
||||
# Changelog for [0.1.0] (2020-02-28)
|
||||
|
||||
The following sections list the changes in ocis-glauth 0.1.0.
|
||||
|
||||
[0.1.0]: https://github.com/owncloud/ocis-glauth/compare/178b6ccde34b64a88e8c14a9acb5857a4c6a3164...v0.1.0
|
||||
|
||||
## Summary
|
||||
|
||||
* Enhancement - Initial release of basic version: [#1](https://github.com/owncloud/ocis-glauth/pull/1)
|
||||
|
||||
## Details
|
||||
|
||||
* Enhancement - Initial release of basic version: [#1](https://github.com/owncloud/ocis-glauth/pull/1)
|
||||
|
||||
Just prepare an initial basic version to provide a glauth service.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/1
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
SHELL := bash
|
||||
NAME := ocis-glauth
|
||||
IMPORT := github.com/owncloud/$(NAME)
|
||||
BIN := bin
|
||||
DIST := dist
|
||||
HUGO := hugo
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
EXECUTABLE := $(NAME).exe
|
||||
UNAME := Windows
|
||||
else
|
||||
EXECUTABLE := $(NAME)
|
||||
UNAME := $(shell uname -s)
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME), Darwin)
|
||||
GOBUILD ?= go build -i
|
||||
else
|
||||
GOBUILD ?= go build
|
||||
endif
|
||||
|
||||
PACKAGES ?= $(shell go list ./...)
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f -not -path "./node_modules/*")
|
||||
GENERATE ?= $(PACKAGES)
|
||||
|
||||
TAGS ?=
|
||||
|
||||
ifndef OUTPUT
|
||||
ifneq ($(DRONE_TAG),)
|
||||
OUTPUT ?= $(subst v,,$(DRONE_TAG))
|
||||
else
|
||||
OUTPUT ?= testing
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef VERSION
|
||||
ifneq ($(DRONE_TAG),)
|
||||
VERSION ?= $(subst v,,$(DRONE_TAG))
|
||||
else
|
||||
VERSION ?= $(shell git rev-parse --short HEAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef DATE
|
||||
DATE := $(shell date -u '+%Y%m%d')
|
||||
endif
|
||||
|
||||
LDFLAGS += -s -w -X "$(IMPORT)/pkg/version.String=$(VERSION)" -X "$(IMPORT)/pkg/version.Date=$(DATE)"
|
||||
GCFLAGS += all=-N -l
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
.PHONY: sync
|
||||
sync:
|
||||
go mod download
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
go clean -i ./...
|
||||
rm -rf $(BIN) $(DIST) $(HUGO)
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
gofmt -s -w $(SOURCES)
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
go vet $(PACKAGES)
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck:
|
||||
go run honnef.co/go/tools/cmd/staticcheck -tags '$(TAGS)' $(PACKAGES)
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
for PKG in $(PACKAGES); do go run golang.org/x/lint/golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
.PHONY: generate
|
||||
generate:
|
||||
go generate $(GENERATE)
|
||||
|
||||
.PHONY: changelog
|
||||
changelog:
|
||||
go run github.com/restic/calens >| CHANGELOG.md
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go run github.com/haya14busa/goverage -v -coverprofile coverage.out $(PACKAGES)
|
||||
|
||||
.PHONY: install
|
||||
install: $(SOURCES)
|
||||
go install -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' ./cmd/$(NAME)
|
||||
|
||||
.PHONY: build
|
||||
build: $(BIN)/$(EXECUTABLE) $(BIN)/$(EXECUTABLE)-debug
|
||||
|
||||
$(BIN)/$(EXECUTABLE): $(SOURCES)
|
||||
$(GOBUILD) -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -o $@ ./cmd/$(NAME)
|
||||
|
||||
$(BIN)/$(EXECUTABLE)-debug: $(SOURCES)
|
||||
$(GOBUILD) -v -tags '$(TAGS)' -ldflags '$(LDFLAGS)' -gcflags '$(GCFLAGS)' -o $@ ./cmd/$(NAME)
|
||||
|
||||
.PHONY: release
|
||||
release: release-dirs release-linux release-windows release-darwin release-copy release-check
|
||||
|
||||
.PHONY: release-dirs
|
||||
release-dirs:
|
||||
mkdir -p $(DIST)/binaries $(DIST)/release
|
||||
|
||||
.PHONY: release-linux
|
||||
release-linux: release-dirs
|
||||
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'linux' -arch 'amd64 386 arm64 arm' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
|
||||
|
||||
.PHONY: release-windows
|
||||
release-windows: release-dirs
|
||||
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '-extldflags "-static" $(LDFLAGS)' -os 'windows' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
|
||||
|
||||
.PHONY: release-darwin
|
||||
release-darwin: release-dirs
|
||||
go run github.com/mitchellh/gox -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -os 'darwin' -arch 'amd64' -output '$(DIST)/binaries/$(EXECUTABLE)-$(OUTPUT)-{{.OS}}-{{.Arch}}' ./cmd/$(NAME)
|
||||
|
||||
.PHONY: release-copy
|
||||
release-copy:
|
||||
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
|
||||
|
||||
.PHONY: release-check
|
||||
release-check:
|
||||
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
|
||||
|
||||
.PHONY: release-finish
|
||||
release-finish: release-copy release-check
|
||||
|
||||
.PHONY: docs-copy
|
||||
docs-copy:
|
||||
mkdir -p $(HUGO); \
|
||||
mkdir -p $(HUGO)/content/extensions; \
|
||||
cd $(HUGO); \
|
||||
git init; \
|
||||
git remote rm origin; \
|
||||
git remote add origin https://github.com/owncloud/owncloud.github.io; \
|
||||
git fetch; \
|
||||
git checkout origin/source -f; \
|
||||
rsync --delete -ax ../docs/ content/extensions/$(NAME)
|
||||
|
||||
.PHONY: docs-build
|
||||
docs-build:
|
||||
cd $(HUGO); hugo
|
||||
|
||||
.PHONY: docs
|
||||
docs: docs-copy docs-build
|
||||
|
||||
.PHONY: watch
|
||||
watch:
|
||||
go run github.com/cespare/reflex -c reflex.conf
|
||||
|
||||
# $(GOPATH)/bin/protoc-gen-go:
|
||||
# GO111MODULE=off go get -v github.com/golang/protobuf/protoc-gen-go
|
||||
|
||||
# $(GOPATH)/bin/protoc-gen-micro:
|
||||
# GO111MODULE=off go get -v github.com/micro/protoc-gen-micro
|
||||
|
||||
# $(GOPATH)/bin/protoc-gen-microweb:
|
||||
# GO111MODULE=off go get -v github.com/webhippie/protoc-gen-microweb
|
||||
|
||||
# $(GOPATH)/bin/protoc-gen-swagger:
|
||||
# GO111MODULE=off go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger
|
||||
|
||||
# pkg/proto/v0/example.pb.go: pkg/proto/v0/example.proto
|
||||
# protoc \
|
||||
# -I=third_party/ \
|
||||
# -I=pkg/proto/v0/ \
|
||||
# --go_out=pkg/proto/v0 example.proto
|
||||
|
||||
# pkg/proto/v0/example.pb.micro.go: pkg/proto/v0/example.proto
|
||||
# protoc \
|
||||
# -I=third_party/ \
|
||||
# -I=pkg/proto/v0/ \
|
||||
# --micro_out=pkg/proto/v0 example.proto
|
||||
|
||||
# pkg/proto/v0/example.pb.web.go: pkg/proto/v0/example.proto
|
||||
# protoc \
|
||||
# -I=third_party/ \
|
||||
# -I=pkg/proto/v0/ \
|
||||
# --microweb_out=pkg/proto/v0 example.proto
|
||||
|
||||
# pkg/proto/v0/example.swagger.json: pkg/proto/v0/example.proto
|
||||
# protoc \
|
||||
# -I=third_party/ \
|
||||
# -I=pkg/proto/v0/ \
|
||||
# --swagger_out=pkg/proto/v0 example.proto
|
||||
|
||||
# .PHONY: protobuf
|
||||
# protobuf: $(GOPATH)/bin/protoc-gen-go $(GOPATH)/bin/protoc-gen-micro $(GOPATH)/bin/protoc-gen-microweb $(GOPATH)/bin/protoc-gen-swagger pkg/proto/v0/example.pb.go pkg/proto/v0/example.pb.micro.go pkg/proto/v0/example.pb.web.go pkg/proto/v0/example.swagger.json
|
||||
@@ -0,0 +1,45 @@
|
||||
# ownCloud Infinite Scale: GLAuth
|
||||
|
||||
[](https://cloud.drone.io/owncloud/ocis-glauth)
|
||||
[](https://gitter.im/cs3org/reva)
|
||||
[](https://www.codacy.com/manual/owncloud/ocis-glauth?utm_source=github.com&utm_medium=referral&utm_content=owncloud/ocis-glauth&utm_campaign=Badge_Grade)
|
||||
[](http://godoc.org/github.com/owncloud/ocis-glauth)
|
||||
[](http://goreportcard.com/report/github.com/owncloud/ocis-glauth)
|
||||
[](http://microbadger.com/images/owncloud/ocis-glauth "Get your own image badge on microbadger.com")
|
||||
|
||||
**This project is under heavy development, it's not in a working state yet!**
|
||||
|
||||
## Install
|
||||
|
||||
You can download prebuilt binaries from the GitHub releases or from our [download mirrors](http://download.owncloud.com/ocis/glauth/). For instructions how to install this on your platform you should take a look at our [documentation](https://owncloud.github.io/extensions/ocis_glauth/)
|
||||
|
||||
## Development
|
||||
|
||||
Make sure you have a working Go environment, for further reference or a guide take a look at the [install instructions](http://golang.org/doc/install.html). This project requires Go >= v1.13.
|
||||
|
||||
```console
|
||||
git clone https://github.com/owncloud/ocis-glauth.git
|
||||
cd ocis-glauth
|
||||
|
||||
make generate build
|
||||
|
||||
./bin/ocis-glauth -h
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
If you find a security issue please contact security@owncloud.com first.
|
||||
|
||||
## Contributing
|
||||
|
||||
Fork -> Patch -> Push -> Pull Request
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
|
||||
## Copyright
|
||||
|
||||
```console
|
||||
Copyright (c) 2019 ownCloud GmbH <https://owncloud.com>
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
Enhancement: Initial release of basic version
|
||||
|
||||
Just prepare an initial basic version to provide a glauth service.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/1
|
||||
@@ -0,0 +1,7 @@
|
||||
Change: Default to config based user backend
|
||||
|
||||
We changed the default configuration to use the config file backend instead of the ownCloud backend.
|
||||
|
||||
The config backend currently only has two hard coded users: demo and admin. To switch back to the ownCloud backend use `GLAUTH_BACKEND_DATASTORE=owncloud`
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/6
|
||||
@@ -0,0 +1,5 @@
|
||||
Change: use physicist demo users
|
||||
|
||||
Demo users like admin, demo and test don't allow you to tell a story. Which is why we changed the set of hard coded demo users to `einstein`, `marie` and `feynman`. You should know who they are. This also changes the ldap domain from `dc=owncloud,dc=com` to `dc=example,dc=org` because that is what these users use as their email domain. There are also `konnectd` and `reva` for technical purposes, eg. to allow konnectd and reva to bind to glauth.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/5
|
||||
@@ -0,0 +1,5 @@
|
||||
Enhancement: Configuration
|
||||
|
||||
Extensions should be responsible of configuring themselves. We use Viper for config loading from default paths. Environment variables **WILL** take precedence over config files.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/11
|
||||
@@ -0,0 +1,5 @@
|
||||
Enhancement: Improve default settings
|
||||
|
||||
This helps achieve zero-config in single-binary.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
@@ -0,0 +1,5 @@
|
||||
Enhancement: Generate temporary ldap certificates if LDAPS is enabled
|
||||
|
||||
This change helps to achieve zero-configuration in single-binary mode.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
@@ -0,0 +1,6 @@
|
||||
Enhancement: Provide additional tls-endpoint
|
||||
|
||||
ocis-glauth is now able to concurrently serve a encrypted and an unencrypted ldap-port. Please note that only
|
||||
SSL (no StarTLS) is supported at the moment.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/12
|
||||
@@ -0,0 +1,6 @@
|
||||
Enhancement: handle ownCloudUUID attribute
|
||||
|
||||
Clients can now query an accounts immutable id by using the [new `ownCloudUUID` attribute](https://github.com/butonic/owncloud-ldap-schema/blob/master/owncloud.schema#L28-L34).
|
||||
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/27
|
||||
@@ -0,0 +1,5 @@
|
||||
Bugfix: ignore case when comparing objectclass values
|
||||
|
||||
The LDAP equality comparison is specified as case insensitive. We fixed the comparison for objectclass properties.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/26
|
||||
@@ -0,0 +1,6 @@
|
||||
Enhancement: implement group queries
|
||||
|
||||
Refactored the handler and implemented group queries.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/22
|
||||
https://github.com/owncloud/ocis-glauth/pull/23
|
||||
@@ -0,0 +1,5 @@
|
||||
Bugfix: build docker images with alpine:latest instead of alpine:edge
|
||||
|
||||
ARM builds were failing when built on alpine:edge, so we switched to alpine:latest instead.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/24
|
||||
@@ -0,0 +1,53 @@
|
||||
{{ $allVersions := . }}
|
||||
{{- range $index, $changes := . }}{{ with $changes -}}
|
||||
{{ if gt (len $allVersions) 1 -}}
|
||||
# Changelog for [{{ .Version }}] ({{ .Date }})
|
||||
|
||||
The following sections list the changes in ocis-glauth {{ .Version }}.
|
||||
|
||||
{{/* creating version compare links */ -}}
|
||||
{{ $next := add1 $index -}}
|
||||
{{ if ne (len $allVersions) $next -}}
|
||||
{{ $previousVersion := (index $allVersions $next).Version -}}
|
||||
{{ if eq .Version "unreleased" -}}
|
||||
[{{ .Version }}]: https://github.com/owncloud/ocis-glauth/compare/v{{ $previousVersion }}...master
|
||||
|
||||
{{ else -}}
|
||||
[{{ .Version }}]: https://github.com/owncloud/ocis-glauth/compare/v{{ $previousVersion }}...v{{ .Version }}
|
||||
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
{{- /* last version managed by calens, end of the loop */ -}}
|
||||
{{ if eq .Version "0.1.0" -}}
|
||||
[{{ .Version }}]: https://github.com/owncloud/ocis-glauth/compare/178b6ccde34b64a88e8c14a9acb5857a4c6a3164...v{{ .Version }}
|
||||
|
||||
{{ end -}}
|
||||
{{ else -}}
|
||||
# Changes in {{ .Version }}
|
||||
|
||||
{{ end -}}
|
||||
|
||||
## Summary
|
||||
{{ range $entry := .Entries }}{{ with $entry }}
|
||||
* {{ .Type }} - {{ .Title }}: [#{{ .PrimaryID }}]({{ .PrimaryURL }})
|
||||
{{- end }}{{ end }}
|
||||
|
||||
## Details
|
||||
{{ range $entry := .Entries }}{{ with $entry }}
|
||||
* {{ .Type }} - {{ .Title }}: [#{{ .PrimaryID }}]({{ .PrimaryURL }})
|
||||
{{ range $par := .Paragraphs }}
|
||||
{{ wrapIndent $par 80 3 }}
|
||||
{{ end -}}
|
||||
{{ range $url := .IssueURLs }}
|
||||
{{ $url -}}
|
||||
{{ end -}}
|
||||
{{ range $url := .PRURLs }}
|
||||
{{ $url -}}
|
||||
{{ end -}}
|
||||
{{ range $url := .OtherURLs }}
|
||||
{{ $url -}}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}{{ end -}}
|
||||
{{ end }}{{ end -}}
|
||||
@@ -0,0 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
We are using [calens](https://github.com/restic/calens) to properly generate a
|
||||
changelog before we are tagging a new release. To get an idea how this could
|
||||
look like <https://github.com/restic/restic/tree/master/changelog> would be the
|
||||
best reference.
|
||||
@@ -0,0 +1,11 @@
|
||||
Bugfix: Fix behavior for foobar (in present tense)
|
||||
|
||||
We've fixed the behavior for foobar, a long-standing annoyance for users. The
|
||||
text should be wrapped at 80 characters length.
|
||||
|
||||
The text in the paragraphs is written in past tense. The last section is a list
|
||||
of issue URLs, PR URLs and other URLs. The first issue ID (or the first PR ID,
|
||||
in case there aren't any issue links) is used as the primary ID.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/1234
|
||||
https://github.com/owncloud/ocis-glauth/pull/55555
|
||||
@@ -0,0 +1,5 @@
|
||||
Bugfix: return invalid credentials when user was not found
|
||||
|
||||
We were relying on an error code of the ListAccounts call when the username and password was wrong. But the list will be empty if no user with the given login was found. So we also need to check if the list of accounts is empty.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/30
|
||||
@@ -0,0 +1,7 @@
|
||||
Bugfix: query numeric attribute values without quotes
|
||||
|
||||
Some LDAP properties like `uidnumber` and `gidnumber` are numeric. When an OS tries to look up a user it will not only try to lookup the user by username, but also by the `uidnumber`: `(&(objectclass=posixAccount)(uidnumber=20000))`. The accounts backend for glauth was sending that as a string query `uid_number eq '20000'` in the ListAccounts query. This PR changes that to `uid_number eq 20000`. The removed quotes allow the parser in ocis-accounts to identify the numeric literal.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/issues/28
|
||||
https://github.com/owncloud/ocis-glauth/pull/29
|
||||
https://github.com/owncloud/ocis-accounts/pull/68
|
||||
@@ -0,0 +1,6 @@
|
||||
Bugfix: Use searchBaseDN if already a user/group name
|
||||
|
||||
In case of the searchBaseDN already referencing a user or group, the search query was ignoring the user/group name entirely, because the searchBaseDN is not part of the LDAP filters. We fixed this by including an additional query part if the searchBaseDN contains a CN.
|
||||
|
||||
https://github.com/owncloud/product/issues/214
|
||||
https://github.com/owncloud/ocis-glauth/pull/32
|
||||
@@ -0,0 +1,5 @@
|
||||
Bugfix: fix LDAP substring startswith filters
|
||||
|
||||
Filters like `(mail=mar*)` are currentld not parsed correctly, but they are used when searching for recipients. This PR correctly converts them to odata filters like `startswith(mail,'mar')`.
|
||||
|
||||
https://github.com/owncloud/ocis-glauth/pull/31
|
||||
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/owncloud/ocis-glauth/pkg/command"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := command.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"debug": {
|
||||
"addr": "0.0.0.0:9124",
|
||||
"token": "",
|
||||
"pprof": false,
|
||||
"zpages": false
|
||||
},
|
||||
"http": {
|
||||
"addr": "0.0.0.0:9120"
|
||||
},
|
||||
"tracing": {
|
||||
"enabled": false,
|
||||
"type": "jaeger",
|
||||
"endpoint": "localhost:6831",
|
||||
"collector": "http://localhost:14268/api/traces",
|
||||
"service": "glauth"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
debug:
|
||||
addr: 0.0.0.0:9124
|
||||
token:
|
||||
pprof: false
|
||||
zpages: false
|
||||
|
||||
http:
|
||||
addr: 0.0.0.0:9120
|
||||
|
||||
tracing:
|
||||
enabled: false
|
||||
type: jaeger
|
||||
endpoint: localhost:6831
|
||||
collector: http://localhost:14268/api/traces
|
||||
service: glauth
|
||||
|
||||
...
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM amd64/alpine:latest
|
||||
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add ca-certificates mailcap && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
echo 'hosts: files dns' >| /etc/nsswitch.conf
|
||||
|
||||
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
|
||||
org.label-schema.name="oCIS GLAuth" \
|
||||
org.label-schema.vendor="ownCloud GmbH" \
|
||||
org.label-schema.schema-version="1.0"
|
||||
|
||||
EXPOSE 9120 9124
|
||||
|
||||
ENTRYPOINT ["/usr/bin/ocis-glauth"]
|
||||
CMD ["server"]
|
||||
|
||||
COPY bin/ocis-glauth /usr/bin/ocis-glauth
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM arm32v6/alpine:latest
|
||||
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add ca-certificates mailcap && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
echo 'hosts: files dns' >| /etc/nsswitch.conf
|
||||
|
||||
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
|
||||
org.label-schema.name="oCIS GLAuth" \
|
||||
org.label-schema.vendor="ownCloud GmbH" \
|
||||
org.label-schema.schema-version="1.0"
|
||||
|
||||
EXPOSE 9120 9124
|
||||
|
||||
ENTRYPOINT ["/usr/bin/ocis-glauth"]
|
||||
CMD ["server"]
|
||||
|
||||
COPY bin/ocis-glauth /usr/bin/ocis-glauth
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM arm64v8/alpine:latest
|
||||
|
||||
RUN apk update && \
|
||||
apk upgrade && \
|
||||
apk add ca-certificates mailcap && \
|
||||
rm -rf /var/cache/apk/* && \
|
||||
echo 'hosts: files dns' >| /etc/nsswitch.conf
|
||||
|
||||
LABEL maintainer="ownCloud GmbH <devops@owncloud.com>" \
|
||||
org.label-schema.name="oCIS GLAuth" \
|
||||
org.label-schema.vendor="ownCloud GmbH" \
|
||||
org.label-schema.schema-version="1.0"
|
||||
|
||||
EXPOSE 9120 9124
|
||||
|
||||
ENTRYPOINT ["/usr/bin/ocis-glauth"]
|
||||
CMD ["server"]
|
||||
|
||||
COPY bin/ocis-glauth /usr/bin/ocis-glauth
|
||||
@@ -0,0 +1,22 @@
|
||||
image: owncloud/ocis-glauth:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
|
||||
{{#if build.tags}}
|
||||
tags:
|
||||
{{#each build.tags}}
|
||||
- {{this}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
manifests:
|
||||
- image: owncloud/ocis-glauth:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
|
||||
platform:
|
||||
architecture: amd64
|
||||
os: linux
|
||||
- image: owncloud/ocis-glauth:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
|
||||
platform:
|
||||
architecture: arm64
|
||||
variant: v8
|
||||
os: linux
|
||||
- image: owncloud/ocis-glauth:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm
|
||||
platform:
|
||||
architecture: arm
|
||||
variant: v6
|
||||
os: linux
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "GLAuth"
|
||||
date: 2018-05-02T00:00:00+00:00
|
||||
weight: 10
|
||||
geekdocRepo: https://github.com/owncloud/ocis-glauth
|
||||
geekdocEditPath: edit/master/docs
|
||||
geekdocFilePath: _index.md
|
||||
---
|
||||
|
||||
This service provides a simple glauth world API which can be used by clients or other extensions.
|
||||
|
||||
- reiner proxy
|
||||
ldap für eos und firewall
|
||||
- backend ist der accounts service
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: "Building"
|
||||
date: 2018-05-02T00:00:00+00:00
|
||||
weight: 30
|
||||
geekdocRepo: https://github.com/owncloud/ocis-glauth
|
||||
geekdocEditPath: edit/master/docs
|
||||
geekdocFilePath: building.md
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
As this project is built with Go, so you need to install that first. The installation of Go is out of the scope of this document, please follow the official documentation for [Go](https://golang.org/doc/install), to build this project you have to install Go >= v1.13. After the installation of the required tools you need to get the sources:
|
||||
|
||||
{{< highlight txt >}}
|
||||
git clone https://github.com/owncloud/ocis-glauth.git
|
||||
cd ocis-glauth
|
||||
{{< / highlight >}}
|
||||
|
||||
All required tool besides Go itself and make are bundled or getting automatically installed within the `GOPATH`. All commands to build this project are part of our `Makefile`.
|
||||
|
||||
## Backend
|
||||
|
||||
{{< highlight txt >}}
|
||||
make generate
|
||||
make build
|
||||
{{< / highlight >}}
|
||||
|
||||
Finally you should have the binary within the `bin/` folder now, give it a try with `./bin/ocis-glauth -h` to see all available options.
|
||||
@@ -0,0 +1,272 @@
|
||||
---
|
||||
title: "Getting Started"
|
||||
date: 2018-05-02T00:00:00+00:00
|
||||
weight: 20
|
||||
geekdocRepo: https://github.com/owncloud/ocis-glauth
|
||||
geekdocEditPath: edit/master/docs
|
||||
geekdocFilePath: getting-started.md
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Installation
|
||||
|
||||
So far we are offering two different variants for the installation. You can choose between [Docker](https://www.docker.com/) or pre-built binaries which are stored on our download mirrors and GitHub releases. Maybe we will also provide system packages for the major distributions later if we see the need for it.
|
||||
|
||||
### Docker
|
||||
|
||||
TBD
|
||||
|
||||
### Binaries
|
||||
|
||||
TBD
|
||||
|
||||
## Configuration
|
||||
|
||||
We provide overall three different variants of configuration. The variant based on environment variables and commandline flags are split up into global values and command-specific values.
|
||||
|
||||
### Envrionment variables
|
||||
|
||||
If you prefer to configure the service with environment variables you can see the available variables below.
|
||||
|
||||
#### Global
|
||||
|
||||
GLAUTH_CONFIG_FILE
|
||||
: Path to config file, empty default value
|
||||
|
||||
GLAUTH_LOG_LEVEL
|
||||
: Set logging level, defaults to `info`
|
||||
|
||||
GLAUTH_LOG_COLOR
|
||||
: Enable colored logging, defaults to `true`
|
||||
|
||||
GLAUTH_LOG_PRETTY
|
||||
: Enable pretty logging, defaults to `true`
|
||||
|
||||
#### Server
|
||||
|
||||
GLAUTH_TRACING_ENABLED
|
||||
: Enable sending traces, defaults to `false`
|
||||
|
||||
GLAUTH_TRACING_TYPE
|
||||
: Tracing backend type, defaults to `jaeger`
|
||||
|
||||
GLAUTH_TRACING_ENDPOINT
|
||||
: Endpoint for the agent, empty default value
|
||||
|
||||
GLAUTH_TRACING_COLLECTOR
|
||||
: Endpoint for the collector, empty default value
|
||||
|
||||
GLAUTH_TRACING_SERVICE
|
||||
: Service name for tracing, defaults to `glauth`
|
||||
|
||||
GLAUTH_DEBUG_ADDR
|
||||
: Address to bind debug server, defaults to `0.0.0.0:9124`
|
||||
|
||||
GLAUTH_DEBUG_TOKEN
|
||||
: Token to grant metrics access, empty default value
|
||||
|
||||
GLAUTH_DEBUG_PPROF
|
||||
: Enable pprof debugging, defaults to `false`
|
||||
|
||||
GLAUTH_DEBUG_ZPAGES
|
||||
: Enable zpages debugging, defaults to `false`
|
||||
|
||||
GLAUTH_HTTP_ADDR
|
||||
: Address to bind http server, defaults to `0.0.0.0:9120`
|
||||
|
||||
GLAUTH_HTTP_NAMESPACE
|
||||
: The http namespace
|
||||
|
||||
GLAUTH_HTTP_ROOT
|
||||
: Root path of http server, defaults to `/`
|
||||
|
||||
#### Health
|
||||
|
||||
GLAUTH_DEBUG_ADDR
|
||||
: Address to debug endpoint, defaults to `0.0.0.0:9124`
|
||||
|
||||
### Commandline flags
|
||||
|
||||
If you prefer to configure the service with commandline flags you can see the available variables below.
|
||||
|
||||
#### Global
|
||||
|
||||
--config-file
|
||||
: Path to config file, empty default value
|
||||
|
||||
--log-level
|
||||
: Set logging level, defaults to `info`
|
||||
|
||||
--log-color
|
||||
: Enable colored logging, defaults to `true`
|
||||
|
||||
--log-pretty
|
||||
: Enable pretty logging, defaults to `true`
|
||||
|
||||
#### Server
|
||||
|
||||
--tracing-enabled
|
||||
: Enable sending traces, defaults to `false`
|
||||
|
||||
--tracing-type
|
||||
: Tracing backend type, defaults to `jaeger`
|
||||
|
||||
--tracing-endpoint
|
||||
: Endpoint for the agent, empty default value
|
||||
|
||||
--tracing-collector
|
||||
: Endpoint for the collector, empty default value
|
||||
|
||||
--tracing-service
|
||||
: Service name for tracing, defaults to `glauth`
|
||||
|
||||
--debug-addr
|
||||
: Address to bind debug server, defaults to `0.0.0.0:9124`
|
||||
|
||||
--debug-token
|
||||
: Token to grant metrics access, empty default value
|
||||
|
||||
--debug-pprof
|
||||
: Enable pprof debugging, defaults to `false`
|
||||
|
||||
--debug-zpages
|
||||
: Enable zpages debugging, defaults to `false`
|
||||
|
||||
--http-addr
|
||||
: Address to bind http server, defaults to `0.0.0.0:9120`
|
||||
|
||||
--http-namespace
|
||||
: Namespace for internal services communication, defaults to `com.owncloud.web`
|
||||
|
||||
--http-root
|
||||
: Root path of http server, defaults to `/`
|
||||
|
||||
#### Health
|
||||
|
||||
--debug-addr
|
||||
: Address to debug endpoint, defaults to `0.0.0.0:9124`
|
||||
|
||||
### Configuration file
|
||||
|
||||
So far we support the file formats `JSON` and `YAML`, if you want to get a full example configuration just take a look at [our repository](https://github.com/owncloud/ocis-glauth/tree/master/config), there you can always see the latest configuration format. These example configurations include all available options and the default values. The configuration file will be automatically loaded if it's placed at `/etc/ocis/glauth.yml`, `${HOME}/.ocis/glauth.yml` or `$(pwd)/config/glauth.yml`.
|
||||
|
||||
## Usage
|
||||
|
||||
The program provides a few sub-commands on execution. The available configuration methods have already been mentioned above. Generally you can always see a formated help output if you execute the binary via `ocis-glauth --help`.
|
||||
|
||||
### Server
|
||||
|
||||
The server command is used to start the http and debug server on two addresses within a single process. The http server is serving the general webservice while the debug server is used for health check, readiness check and to server the metrics mentioned below. For further help please execute:
|
||||
|
||||
{{< highlight txt >}}
|
||||
ocis-glauth server --help
|
||||
{{< / highlight >}}
|
||||
|
||||
### Health
|
||||
|
||||
The health command is used to execute a health check, if the exit code equals zero the service should be up and running, if the exist code is greater than zero the service is not in a healthy state. Generally this command is used within our Docker containers, it could also be used within Kubernetes.
|
||||
|
||||
{{< highlight txt >}}
|
||||
ocis-glauth health --help
|
||||
{{< / highlight >}}
|
||||
|
||||
## Metrics
|
||||
|
||||
This service provides some [Prometheus](https://prometheus.io/) metrics through the debug endpoint, you can optionally secure the metrics endpoint by some random token, which got to be configured through one of the flag `--debug-token` or the environment variable `GLAUTH_DEBUG_TOKEN` mentioned above. By default the metrics endpoint is bound to `http://0.0.0.0:9124/metrics`.
|
||||
|
||||
go_gc_duration_seconds
|
||||
: A summary of the GC invocation durations
|
||||
|
||||
go_gc_duration_seconds_sum
|
||||
: A summary of the GC invocation durations
|
||||
|
||||
go_gc_duration_seconds_count
|
||||
: A summary of the GC invocation durations
|
||||
|
||||
go_goroutines
|
||||
: Number of goroutines that currently exist
|
||||
|
||||
go_info
|
||||
: Information about the Go environment
|
||||
|
||||
go_memstats_alloc_bytes
|
||||
: Number of bytes allocated and still in use
|
||||
|
||||
go_memstats_alloc_bytes_total
|
||||
: Total number of bytes allocated, even if freed
|
||||
|
||||
go_memstats_buck_hash_sys_bytes
|
||||
: Number of bytes used by the profiling bucket hash table
|
||||
|
||||
go_memstats_frees_total
|
||||
: Total number of frees
|
||||
|
||||
go_memstats_gc_cpu_fraction
|
||||
: The fraction of this program's available CPU time used by the GC since the program started
|
||||
|
||||
go_memstats_gc_sys_bytes
|
||||
: Number of bytes used for garbage collection system metadata
|
||||
|
||||
go_memstats_heap_alloc_bytes
|
||||
: Number of heap bytes allocated and still in use
|
||||
|
||||
go_memstats_heap_idle_bytes
|
||||
: Number of heap bytes waiting to be used
|
||||
|
||||
go_memstats_heap_inuse_bytes
|
||||
: Number of heap bytes that are in use
|
||||
|
||||
go_memstats_heap_objects
|
||||
: Number of allocated objects
|
||||
|
||||
go_memstats_heap_released_bytes
|
||||
: Number of heap bytes released to OS
|
||||
|
||||
go_memstats_heap_sys_bytes
|
||||
: Number of heap bytes obtained from system
|
||||
|
||||
go_memstats_last_gc_time_seconds
|
||||
: Number of seconds since 1970 of last garbage collection
|
||||
|
||||
go_memstats_lookups_total
|
||||
: Total number of pointer lookups
|
||||
|
||||
go_memstats_mallocs_total
|
||||
: Total number of mallocs
|
||||
|
||||
go_memstats_mcache_inuse_bytes
|
||||
: Number of bytes in use by mcache structures
|
||||
|
||||
go_memstats_mcache_sys_bytes
|
||||
: Number of bytes used for mcache structures obtained from system
|
||||
|
||||
go_memstats_mspan_inuse_bytes
|
||||
: Number of bytes in use by mspan structures
|
||||
|
||||
go_memstats_mspan_sys_bytes
|
||||
: Number of bytes used for mspan structures obtained from system
|
||||
|
||||
go_memstats_next_gc_bytes
|
||||
: Number of heap bytes when next garbage collection will take place
|
||||
|
||||
go_memstats_other_sys_bytes
|
||||
: Number of bytes used for other system allocations
|
||||
|
||||
go_memstats_stack_inuse_bytes
|
||||
: Number of bytes in use by the stack allocator
|
||||
|
||||
go_memstats_stack_sys_bytes
|
||||
: Number of bytes obtained from system for stack allocator
|
||||
|
||||
go_memstats_sys_bytes
|
||||
: Number of bytes obtained from system
|
||||
|
||||
go_threads
|
||||
: Number of OS threads created
|
||||
|
||||
promhttp_metric_handler_requests_in_flight
|
||||
: Current number of scrapes being served
|
||||
|
||||
promhttp_metric_handler_requests_total
|
||||
: Total number of scrapes by HTTP status code
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
title: "License"
|
||||
date: 2018-05-02T00:00:00+00:00
|
||||
weight: 40
|
||||
geekdocRepo: https://github.com/owncloud/ocis-glauth
|
||||
geekdocEditPath: edit/master/docs
|
||||
geekdocFilePath: license.md
|
||||
---
|
||||
|
||||
This project is licensed under the [Apache 2.0](https://github.com/owncloud/ocis-glauth/blob/master/LICENSE) license. For the license of the used libraries you have to check the respective sources.
|
||||
@@ -0,0 +1,28 @@
|
||||
module github.com/owncloud/ocis-glauth
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
contrib.go.opencensus.io/exporter/jaeger v0.2.0
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.7.0
|
||||
contrib.go.opencensus.io/exporter/zipkin v0.1.1
|
||||
github.com/GeertJohan/yubigo v0.0.0-20190917122436-175bc097e60e
|
||||
github.com/UnnoTed/fileb0x v1.1.4
|
||||
github.com/glauth/glauth v1.1.3-0.20200228160118-2d4f5d547682
|
||||
github.com/go-logr/logr v0.1.0
|
||||
github.com/micro/cli/v2 v2.1.2
|
||||
github.com/micro/go-micro/v2 v2.6.0
|
||||
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
|
||||
github.com/nmcclain/ldap v0.0.0-20191021200707-3b3b69a7e9e3
|
||||
github.com/oklog/run v1.1.0
|
||||
github.com/openzipkin/zipkin-go v0.2.2
|
||||
github.com/owncloud/ocis-accounts v0.1.2-0.20200710152724-fa35a81beb2f
|
||||
github.com/owncloud/ocis-pkg/v2 v2.2.2-0.20200602070144-cd0620668170
|
||||
github.com/restic/calens v0.2.0
|
||||
github.com/rs/zerolog v1.19.0
|
||||
github.com/spf13/viper v1.7.0
|
||||
go.opencensus.io v0.22.4
|
||||
golang.org/x/tools v0.0.0-20200427214658-4697a2867c88 // indirect
|
||||
)
|
||||
|
||||
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
|
||||
+1442
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/micro/cli/v2"
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
"github.com/owncloud/ocis-glauth/pkg/flagset"
|
||||
)
|
||||
|
||||
// Health is the entrypoint for the health command.
|
||||
func Health(cfg *config.Config) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "health",
|
||||
Usage: "Check health status",
|
||||
Flags: flagset.HealthWithConfig(cfg),
|
||||
Action: func(c *cli.Context) error {
|
||||
logger := NewLogger(cfg)
|
||||
|
||||
resp, err := http.Get(
|
||||
fmt.Sprintf(
|
||||
"http://%s/healthz",
|
||||
cfg.Debug.Addr,
|
||||
),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Fatal().
|
||||
Err(err).
|
||||
Msg("Failed to request health check")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
logger.Fatal().
|
||||
Int("code", resp.StatusCode).
|
||||
Msg("Health seems to be in bad state")
|
||||
}
|
||||
|
||||
logger.Debug().
|
||||
Int("code", resp.StatusCode).
|
||||
Msg("Health got a good state")
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/cli/v2"
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
"github.com/owncloud/ocis-glauth/pkg/flagset"
|
||||
"github.com/owncloud/ocis-glauth/pkg/version"
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Execute is the entry point for the ocis-glauth command.
|
||||
func Execute() error {
|
||||
cfg := config.New()
|
||||
|
||||
app := &cli.App{
|
||||
Name: "ocis-glauth",
|
||||
Version: version.String,
|
||||
Usage: "Serve GLAuth API for oCIS",
|
||||
Compiled: version.Compiled(),
|
||||
|
||||
Authors: []*cli.Author{
|
||||
{
|
||||
Name: "ownCloud GmbH",
|
||||
Email: "support@owncloud.com",
|
||||
},
|
||||
},
|
||||
|
||||
Flags: flagset.RootWithConfig(cfg),
|
||||
|
||||
Before: func(c *cli.Context) error {
|
||||
return ParseConfig(c, cfg)
|
||||
},
|
||||
|
||||
Commands: []*cli.Command{
|
||||
Server(cfg),
|
||||
Health(cfg),
|
||||
},
|
||||
}
|
||||
|
||||
cli.HelpFlag = &cli.BoolFlag{
|
||||
Name: "help,h",
|
||||
Usage: "Show the help",
|
||||
}
|
||||
|
||||
cli.VersionFlag = &cli.BoolFlag{
|
||||
Name: "version,v",
|
||||
Usage: "Print the version",
|
||||
}
|
||||
|
||||
return app.Run(os.Args)
|
||||
}
|
||||
|
||||
// NewLogger initializes a service-specific logger instance.
|
||||
func NewLogger(cfg *config.Config) log.Logger {
|
||||
return log.NewLogger(
|
||||
log.Name("glauth"),
|
||||
log.Level(cfg.Log.Level),
|
||||
log.Pretty(cfg.Log.Pretty),
|
||||
log.Color(cfg.Log.Color),
|
||||
)
|
||||
}
|
||||
|
||||
// ParseConfig loads glauth configuration from Viper known paths.
|
||||
func ParseConfig(c *cli.Context, cfg *config.Config) error {
|
||||
logger := NewLogger(cfg)
|
||||
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.SetEnvPrefix("GLAUTH")
|
||||
viper.AutomaticEnv()
|
||||
|
||||
if c.IsSet("config-file") {
|
||||
viper.SetConfigFile(c.String("config-file"))
|
||||
} else {
|
||||
viper.SetConfigName("glauth")
|
||||
|
||||
viper.AddConfigPath("/etc/ocis")
|
||||
viper.AddConfigPath("$HOME/.ocis")
|
||||
viper.AddConfigPath("./config")
|
||||
}
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
switch err.(type) {
|
||||
case viper.ConfigFileNotFoundError:
|
||||
logger.Info().
|
||||
Msg("Continue without config")
|
||||
case viper.UnsupportedConfigError:
|
||||
logger.Fatal().
|
||||
Err(err).
|
||||
Msg("Unsupported config type")
|
||||
default:
|
||||
logger.Fatal().
|
||||
Err(err).
|
||||
Msg("Failed to read config")
|
||||
}
|
||||
}
|
||||
|
||||
if err := viper.Unmarshal(&cfg); err != nil {
|
||||
logger.Fatal().
|
||||
Err(err).
|
||||
Msg("Failed to parse config")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/owncloud/ocis-glauth/pkg/crypto"
|
||||
|
||||
"contrib.go.opencensus.io/exporter/jaeger"
|
||||
"contrib.go.opencensus.io/exporter/ocagent"
|
||||
"contrib.go.opencensus.io/exporter/zipkin"
|
||||
glauthcfg "github.com/glauth/glauth/pkg/config"
|
||||
|
||||
"github.com/micro/cli/v2"
|
||||
"github.com/micro/go-micro/v2"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/oklog/run"
|
||||
openzipkin "github.com/openzipkin/zipkin-go"
|
||||
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
|
||||
accounts "github.com/owncloud/ocis-accounts/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
"github.com/owncloud/ocis-glauth/pkg/flagset"
|
||||
"github.com/owncloud/ocis-glauth/pkg/server/debug"
|
||||
"github.com/owncloud/ocis-glauth/pkg/server/glauth"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// Server is the entrypoint for the server command.
|
||||
func Server(cfg *config.Config) *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "server",
|
||||
Usage: "Start integrated server",
|
||||
Flags: flagset.ServerWithConfig(cfg),
|
||||
Before: func(c *cli.Context) error {
|
||||
if cfg.HTTP.Root != "/" {
|
||||
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
|
||||
}
|
||||
|
||||
return ParseConfig(c, cfg)
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
logger := NewLogger(cfg)
|
||||
|
||||
if cfg.Tracing.Enabled {
|
||||
switch t := cfg.Tracing.Type; t {
|
||||
case "agent":
|
||||
exporter, err := ocagent.NewExporter(
|
||||
ocagent.WithReconnectionPeriod(5*time.Second),
|
||||
ocagent.WithAddress(cfg.Tracing.Endpoint),
|
||||
ocagent.WithServiceName(cfg.Tracing.Service),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Err(err).
|
||||
Str("endpoint", cfg.Tracing.Endpoint).
|
||||
Str("collector", cfg.Tracing.Collector).
|
||||
Msg("Failed to create agent tracing")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
trace.RegisterExporter(exporter)
|
||||
view.RegisterExporter(exporter)
|
||||
|
||||
case "jaeger":
|
||||
exporter, err := jaeger.NewExporter(
|
||||
jaeger.Options{
|
||||
AgentEndpoint: cfg.Tracing.Endpoint,
|
||||
CollectorEndpoint: cfg.Tracing.Collector,
|
||||
ServiceName: cfg.Tracing.Service,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Err(err).
|
||||
Str("endpoint", cfg.Tracing.Endpoint).
|
||||
Str("collector", cfg.Tracing.Collector).
|
||||
Msg("Failed to create jaeger tracing")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
trace.RegisterExporter(exporter)
|
||||
|
||||
case "zipkin":
|
||||
endpoint, err := openzipkin.NewEndpoint(
|
||||
cfg.Tracing.Service,
|
||||
cfg.Tracing.Endpoint,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Error().
|
||||
Err(err).
|
||||
Str("endpoint", cfg.Tracing.Endpoint).
|
||||
Str("collector", cfg.Tracing.Collector).
|
||||
Msg("Failed to create zipkin tracing")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
exporter := zipkin.NewExporter(
|
||||
zipkinhttp.NewReporter(
|
||||
cfg.Tracing.Collector,
|
||||
),
|
||||
endpoint,
|
||||
)
|
||||
|
||||
trace.RegisterExporter(exporter)
|
||||
|
||||
default:
|
||||
logger.Warn().
|
||||
Str("type", t).
|
||||
Msg("Unknown tracing backend")
|
||||
}
|
||||
|
||||
trace.ApplyConfig(
|
||||
trace.Config{
|
||||
DefaultSampler: trace.AlwaysSample(),
|
||||
},
|
||||
)
|
||||
} else {
|
||||
logger.Debug().
|
||||
Msg("Tracing is not enabled")
|
||||
}
|
||||
|
||||
var (
|
||||
gr = run.Group{}
|
||||
ctx, cancel = context.WithCancel(context.Background())
|
||||
//metrics = metrics.New()
|
||||
)
|
||||
|
||||
defer cancel()
|
||||
|
||||
{
|
||||
cfg := glauthcfg.Config{
|
||||
LDAP: glauthcfg.LDAP{
|
||||
Enabled: cfg.Ldap.Enabled,
|
||||
Listen: cfg.Ldap.Address,
|
||||
},
|
||||
LDAPS: glauthcfg.LDAPS{
|
||||
Enabled: cfg.Ldaps.Enabled,
|
||||
Listen: cfg.Ldaps.Address,
|
||||
Cert: cfg.Ldaps.Cert,
|
||||
Key: cfg.Ldaps.Key,
|
||||
},
|
||||
Backend: glauthcfg.Backend{
|
||||
BaseDN: cfg.Backend.BaseDN,
|
||||
Insecure: cfg.Backend.Insecure,
|
||||
NameFormat: cfg.Backend.NameFormat,
|
||||
GroupFormat: cfg.Backend.GroupFormat,
|
||||
SSHKeyAttr: cfg.Backend.SSHKeyAttr,
|
||||
},
|
||||
}
|
||||
|
||||
if cfg.LDAPS.Enabled {
|
||||
// GenCert has side effects as it writes 2 files to the binary running location
|
||||
if err := crypto.GenCert("ldap.crt", "ldap.key", logger); err != nil {
|
||||
logger.Fatal().Err(err).Msgf("Could not generate test-certificate")
|
||||
}
|
||||
}
|
||||
|
||||
as, gs, err := getAccountsServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server, err := glauth.Server(
|
||||
glauth.AccountsService(as),
|
||||
glauth.GroupsService(gs),
|
||||
glauth.Logger(logger),
|
||||
glauth.Config(&cfg),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Info().
|
||||
Err(err).
|
||||
Str("transport", "ldap").
|
||||
Msg("Failed to initialize server")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(func() error {
|
||||
err := make(chan error)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case err <- server.ListenAndServe():
|
||||
return <-err
|
||||
}
|
||||
|
||||
}, func(_ error) {
|
||||
logger.Info().
|
||||
Str("transport", "ldap").
|
||||
Msg("Shutting down server")
|
||||
|
||||
server.Shutdown()
|
||||
cancel()
|
||||
})
|
||||
|
||||
gr.Add(func() error {
|
||||
err := make(chan error)
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case err <- server.ListenAndServeTLS():
|
||||
return <-err
|
||||
}
|
||||
|
||||
}, func(_ error) {
|
||||
logger.Info().
|
||||
Str("transport", "ldaps").
|
||||
Msg("Shutting down server")
|
||||
|
||||
server.Shutdown()
|
||||
cancel()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
server, err := debug.Server(
|
||||
debug.Logger(logger),
|
||||
debug.Context(ctx),
|
||||
debug.Config(cfg),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Info().
|
||||
Err(err).
|
||||
Str("transport", "debug").
|
||||
Msg("Failed to initialize server")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(func() error {
|
||||
return server.ListenAndServe()
|
||||
}, func(_ error) {
|
||||
ctx, timeout := context.WithTimeout(ctx, 5*time.Second)
|
||||
|
||||
defer timeout()
|
||||
defer cancel()
|
||||
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
logger.Info().
|
||||
Err(err).
|
||||
Str("transport", "debug").
|
||||
Msg("Failed to shutdown server")
|
||||
} else {
|
||||
logger.Info().
|
||||
Str("transport", "debug").
|
||||
Msg("Shutting down server")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
stop := make(chan os.Signal, 1)
|
||||
|
||||
gr.Add(func() error {
|
||||
signal.Notify(stop, os.Interrupt)
|
||||
|
||||
<-stop
|
||||
|
||||
return nil
|
||||
}, func(err error) {
|
||||
close(stop)
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
|
||||
return gr.Run()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// getAccountsServices returns an ocis-accounts service
|
||||
func getAccountsServices() (accounts.AccountsService, accounts.GroupsService, error) {
|
||||
service := micro.NewService()
|
||||
|
||||
// parse command line flags
|
||||
service.Init()
|
||||
|
||||
err := service.Client().Init(
|
||||
client.ContentType("application/json"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return accounts.NewAccountsService("com.owncloud.api.accounts", service.Client()),
|
||||
accounts.NewGroupsService("com.owncloud.api.accounts", service.Client()),
|
||||
nil
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package config
|
||||
|
||||
// Log defines the available logging configuration.
|
||||
type Log struct {
|
||||
Level string
|
||||
Pretty bool
|
||||
Color bool
|
||||
}
|
||||
|
||||
// Debug defines the available debug configuration.
|
||||
type Debug struct {
|
||||
Addr string
|
||||
Token string
|
||||
Pprof bool
|
||||
Zpages bool
|
||||
}
|
||||
|
||||
// HTTP defines the available http configuration.
|
||||
type HTTP struct {
|
||||
Addr string
|
||||
Namespace string
|
||||
Root string
|
||||
}
|
||||
|
||||
// Tracing defines the available tracing configuration.
|
||||
type Tracing struct {
|
||||
Enabled bool
|
||||
Type string
|
||||
Endpoint string
|
||||
Collector string
|
||||
Service string
|
||||
}
|
||||
|
||||
// Ldap defined the available LDAP configuration.
|
||||
type Ldap struct {
|
||||
Address string
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
// Ldaps defined the available LDAPS configuration.
|
||||
type Ldaps struct {
|
||||
Ldap
|
||||
Cert string
|
||||
Key string
|
||||
}
|
||||
|
||||
// Backend defined the available backend configuration.
|
||||
type Backend struct {
|
||||
BaseDN string
|
||||
Insecure bool
|
||||
NameFormat string
|
||||
GroupFormat string
|
||||
SSHKeyAttr string
|
||||
}
|
||||
|
||||
// Config combines all available configuration parts.
|
||||
type Config struct {
|
||||
File string
|
||||
Log Log
|
||||
Debug Debug
|
||||
HTTP HTTP
|
||||
Tracing Tracing
|
||||
Ldap Ldap
|
||||
Ldaps Ldaps
|
||||
Backend Backend
|
||||
}
|
||||
|
||||
// New initializes a new configuration with or without defaults.
|
||||
func New() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
)
|
||||
|
||||
func publicKey(priv interface{}) interface{} {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
case *ecdsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func pemBlockForKey(priv interface{}, l log.Logger) *pem.Block {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
|
||||
case *ecdsa.PrivateKey:
|
||||
b, err := x509.MarshalECPrivateKey(k)
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Unable to marshal ECDSA private key")
|
||||
}
|
||||
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GenCert generates TLS-Certificates
|
||||
func GenCert(certName string, keyName string, l log.Logger) error {
|
||||
var priv interface{}
|
||||
var err error
|
||||
|
||||
priv, err = rsa.GenerateKey(rand.Reader, 2048)
|
||||
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to generate private key")
|
||||
}
|
||||
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(24 * time.Hour * 365)
|
||||
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to generate serial number")
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Acme Corp"},
|
||||
CommonName: "OCIS",
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
hosts := []string{"127.0.0.1", "localhost"}
|
||||
for _, h := range hosts {
|
||||
if ip := net.ParseIP(h); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, h)
|
||||
}
|
||||
}
|
||||
|
||||
//template.IsCA = true
|
||||
//template.KeyUsage |= x509.KeyUsageCertSign
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to create certificate")
|
||||
}
|
||||
|
||||
certOut, err := os.Create(certName)
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msgf("Failed to open %v for writing", certName)
|
||||
}
|
||||
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to encode certificate")
|
||||
}
|
||||
err = certOut.Close()
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to write cert")
|
||||
}
|
||||
l.Info().Msg("Written server.crt")
|
||||
|
||||
keyOut, err := os.OpenFile(keyName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msgf("Failed to open %v for writing", keyName)
|
||||
}
|
||||
err = pem.Encode(keyOut, pemBlockForKey(priv, l))
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to encode key")
|
||||
}
|
||||
err = keyOut.Close()
|
||||
if err != nil {
|
||||
l.Fatal().Err(err).Msg("Failed to write key")
|
||||
}
|
||||
l.Info().Msgf("Written %v", keyName)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package flagset
|
||||
|
||||
import (
|
||||
"github.com/micro/cli/v2"
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
)
|
||||
|
||||
// RootWithConfig applies cfg to the root flagset
|
||||
func RootWithConfig(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "config-file",
|
||||
Value: "",
|
||||
Usage: "Path to config file",
|
||||
EnvVars: []string{"GLAUTH_CONFIG_FILE"},
|
||||
Destination: &cfg.File,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "log-level",
|
||||
Value: "info",
|
||||
Usage: "Set logging level",
|
||||
EnvVars: []string{"GLAUTH_LOG_LEVEL"},
|
||||
Destination: &cfg.Log.Level,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Value: true,
|
||||
Name: "log-pretty",
|
||||
Usage: "Enable pretty logging",
|
||||
EnvVars: []string{"GLAUTH_LOG_PRETTY"},
|
||||
Destination: &cfg.Log.Pretty,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Value: true,
|
||||
Name: "log-color",
|
||||
Usage: "Enable colored logging",
|
||||
EnvVars: []string{"GLAUTH_LOG_COLOR"},
|
||||
Destination: &cfg.Log.Color,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// HealthWithConfig applies cfg to the root flagset
|
||||
func HealthWithConfig(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "debug-addr",
|
||||
Value: "0.0.0.0:9129",
|
||||
Usage: "Address to debug endpoint",
|
||||
EnvVars: []string{"GLAUTH_DEBUG_ADDR"},
|
||||
Destination: &cfg.Debug.Addr,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ServerWithConfig applies cfg to the root flagset
|
||||
func ServerWithConfig(cfg *config.Config) []cli.Flag {
|
||||
return []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "tracing-enabled",
|
||||
Usage: "Enable sending traces",
|
||||
EnvVars: []string{"GLAUTH_TRACING_ENABLED"},
|
||||
Destination: &cfg.Tracing.Enabled,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tracing-type",
|
||||
Value: "jaeger",
|
||||
Usage: "Tracing backend type",
|
||||
EnvVars: []string{"GLAUTH_TRACING_TYPE"},
|
||||
Destination: &cfg.Tracing.Type,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tracing-endpoint",
|
||||
Value: "",
|
||||
Usage: "Endpoint for the agent",
|
||||
EnvVars: []string{"GLAUTH_TRACING_ENDPOINT"},
|
||||
Destination: &cfg.Tracing.Endpoint,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tracing-collector",
|
||||
Value: "",
|
||||
Usage: "Endpoint for the collector",
|
||||
EnvVars: []string{"GLAUTH_TRACING_COLLECTOR"},
|
||||
Destination: &cfg.Tracing.Collector,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tracing-service",
|
||||
Value: "glauth",
|
||||
Usage: "Service name for tracing",
|
||||
EnvVars: []string{"GLAUTH_TRACING_SERVICE"},
|
||||
Destination: &cfg.Tracing.Service,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "debug-addr",
|
||||
Value: "0.0.0.0:9129",
|
||||
Usage: "Address to bind debug server",
|
||||
EnvVars: []string{"GLAUTH_DEBUG_ADDR"},
|
||||
Destination: &cfg.Debug.Addr,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "debug-token",
|
||||
Value: "",
|
||||
Usage: "Token to grant metrics access",
|
||||
EnvVars: []string{"GLAUTH_DEBUG_TOKEN"},
|
||||
Destination: &cfg.Debug.Token,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug-pprof",
|
||||
Usage: "Enable pprof debugging",
|
||||
EnvVars: []string{"GLAUTH_DEBUG_PPROF"},
|
||||
Destination: &cfg.Debug.Pprof,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "debug-zpages",
|
||||
Usage: "Enable zpages debugging",
|
||||
EnvVars: []string{"GLAUTH_DEBUG_ZPAGES"},
|
||||
Destination: &cfg.Debug.Zpages,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "ldap-addr",
|
||||
Value: "0.0.0.0:9125",
|
||||
Usage: "Address to bind ldap server",
|
||||
EnvVars: []string{"GLAUTH_LDAP_ADDR"},
|
||||
Destination: &cfg.Ldap.Address,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "ldap-enabled",
|
||||
Value: true,
|
||||
Usage: "Enable ldap server",
|
||||
EnvVars: []string{"GLAUTH_LDAP_ENABLED"},
|
||||
Destination: &cfg.Ldap.Enabled,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "ldaps-addr",
|
||||
Value: "0.0.0.0:9126",
|
||||
Usage: "Address to bind ldap server",
|
||||
EnvVars: []string{"GLAUTH_LDAPS_ADDR"},
|
||||
Destination: &cfg.Ldaps.Address,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "ldaps-enabled",
|
||||
Value: true,
|
||||
Usage: "Enable ldap server",
|
||||
EnvVars: []string{"GLAUTH_LDAPS_ENABLED"},
|
||||
Destination: &cfg.Ldaps.Enabled,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ldaps-cert",
|
||||
Value: "./ldap.crt",
|
||||
Usage: "path to ldaps certificate in PEM format",
|
||||
EnvVars: []string{"GLAUTH_LDAPS_CERT"},
|
||||
Destination: &cfg.Ldaps.Cert,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ldaps-key",
|
||||
Value: "./ldap.key",
|
||||
Usage: "path to ldaps key in PEM format",
|
||||
EnvVars: []string{"GLAUTH_LDAPS_KEY"},
|
||||
Destination: &cfg.Ldaps.Key,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "backend-basedn",
|
||||
Value: "dc=example,dc=org",
|
||||
Usage: "base distinguished name to expose",
|
||||
EnvVars: []string{"GLAUTH_BACKEND_BASEDN"},
|
||||
Destination: &cfg.Backend.BaseDN,
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "backend-insecure",
|
||||
Value: false,
|
||||
Usage: "Allow insecure requests to the datastore",
|
||||
EnvVars: []string{"GLAUTH_BACKEND_INSECURE"},
|
||||
Destination: &cfg.Backend.Insecure,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "backend-name-format",
|
||||
Value: "cn",
|
||||
Usage: "name attribute for entries to expose. typically cn or uid",
|
||||
EnvVars: []string{"GLAUTH_BACKEND_NAME_FORMAT"},
|
||||
Destination: &cfg.Backend.NameFormat,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "backend-group-format",
|
||||
Value: "ou",
|
||||
Usage: "name attribute for entries to expose. typically ou, cn or dc",
|
||||
EnvVars: []string{"GLAUTH_BACKEND_GROUP_FORMAT"},
|
||||
Destination: &cfg.Backend.GroupFormat,
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "backend-ssh-key-attr",
|
||||
Value: "sshPublicKey",
|
||||
Usage: "ssh key attribute for entries to expose",
|
||||
EnvVars: []string{"GLAUTH_BACKEND_SSH_KEY_ATTR"},
|
||||
Destination: &cfg.Backend.SSHKeyAttr,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package metrics
|
||||
|
||||
var (
|
||||
// Namespace defines the namespace for the defines metrics.
|
||||
Namespace = "ocis"
|
||||
|
||||
// Subsystem defines the subsystem for the defines metrics.
|
||||
Subsystem = "glauth"
|
||||
)
|
||||
|
||||
// Metrics defines the available metrics of this service.
|
||||
type Metrics struct {
|
||||
// Counter *prometheus.CounterVec
|
||||
}
|
||||
|
||||
// New initializes the available metrics.
|
||||
func New() *Metrics {
|
||||
m := &Metrics{
|
||||
// Counter: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
// Namespace: Namespace,
|
||||
// Subsystem: Subsystem,
|
||||
// Name: "greet_total",
|
||||
// Help: "How many greeting requests processed",
|
||||
// }, []string{}),
|
||||
}
|
||||
|
||||
// prometheus.Register(
|
||||
// m.Counter,
|
||||
// )
|
||||
|
||||
return m
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package mlogr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
plog "github.com/owncloud/ocis-pkg/v2/log"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
const debugVerbosity = 6
|
||||
const traceVerbosity = 8
|
||||
|
||||
// New returns a logr.Logger which is implemented by the log.
|
||||
func New(l *plog.Logger) logr.Logger {
|
||||
return logger{
|
||||
l: l,
|
||||
verbosity: 0,
|
||||
prefix: "glauth",
|
||||
values: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// logger is a logr.Logger that uses the ocis-pkg log.
|
||||
type logger struct {
|
||||
l *plog.Logger
|
||||
verbosity int
|
||||
prefix string
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
func (l logger) clone() logger {
|
||||
out := l
|
||||
out.values = copySlice(l.values)
|
||||
return out
|
||||
}
|
||||
|
||||
func copySlice(in []interface{}) []interface{} {
|
||||
out := make([]interface{}, len(in))
|
||||
copy(out, in)
|
||||
return out
|
||||
}
|
||||
|
||||
// add converts a bunch of arbitrary key-value pairs into zerolog fields.
|
||||
func add(e *zerolog.Event, keysAndVals []interface{}) {
|
||||
|
||||
// make sure we got an even number of arguments
|
||||
if len(keysAndVals)%2 != 0 {
|
||||
e.Interface("args", keysAndVals).
|
||||
AnErr("zerologr-err", errors.New("odd number of arguments passed as key-value pairs for logging")).
|
||||
Stack()
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(keysAndVals); {
|
||||
// process a key-value pair,
|
||||
// ensuring that the key is a string
|
||||
key, val := keysAndVals[i], keysAndVals[i+1]
|
||||
keyStr, isString := key.(string)
|
||||
if !isString {
|
||||
// if the key isn't a string, log additional error
|
||||
e.Interface("invalid key", key).
|
||||
AnErr("zerologr-err", errors.New("non-string key argument passed to logging, ignoring all later arguments")).
|
||||
Stack()
|
||||
return
|
||||
}
|
||||
e.Interface(keyStr, val)
|
||||
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Info(msg string, keysAndVals ...interface{}) {
|
||||
if l.Enabled() {
|
||||
var e *zerolog.Event
|
||||
if l.verbosity < debugVerbosity {
|
||||
e = l.l.Info()
|
||||
} else if l.verbosity < traceVerbosity {
|
||||
e = l.l.Debug()
|
||||
} else {
|
||||
e = l.l.Trace()
|
||||
}
|
||||
e.Int("verbosity", l.verbosity)
|
||||
if l.prefix != "" {
|
||||
e.Str("name", l.prefix)
|
||||
}
|
||||
add(e, l.values)
|
||||
add(e, keysAndVals)
|
||||
e.Msg(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Enabled() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (l logger) Error(err error, msg string, keysAndVals ...interface{}) {
|
||||
e := l.l.Error().Err(err)
|
||||
if l.prefix != "" {
|
||||
e.Str("name", l.prefix)
|
||||
}
|
||||
add(e, l.values)
|
||||
add(e, keysAndVals)
|
||||
e.Msg(msg)
|
||||
}
|
||||
|
||||
func (l logger) V(verbosity int) logr.InfoLogger {
|
||||
//new := l.clone()
|
||||
//new.level = level
|
||||
//return new
|
||||
l.verbosity = verbosity
|
||||
return l
|
||||
}
|
||||
|
||||
// WithName returns a new logr.Logger with the specified name appended. zerologr
|
||||
// uses '/' characters to separate name elements. Callers should not pass '/'
|
||||
// in the provided name string, but this library does not actually enforce that.
|
||||
func (l logger) WithName(name string) logr.Logger {
|
||||
new := l.clone()
|
||||
if len(l.prefix) > 0 {
|
||||
new.prefix = l.prefix + "/"
|
||||
}
|
||||
new.prefix += name
|
||||
return new
|
||||
}
|
||||
func (l logger) WithValues(kvList ...interface{}) logr.Logger {
|
||||
new := l.clone()
|
||||
new.values = append(new.values, kvList...)
|
||||
return new
|
||||
}
|
||||
|
||||
var _ logr.Logger = logger{}
|
||||
var _ logr.InfoLogger = logger{}
|
||||
@@ -0,0 +1,50 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
// Logger provides a function to set the logger option.
|
||||
func Logger(val log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = val
|
||||
}
|
||||
}
|
||||
|
||||
// Context provides a function to set the context option.
|
||||
func Context(val context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = val
|
||||
}
|
||||
}
|
||||
|
||||
// Config provides a function to set the config option.
|
||||
func Config(val *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/owncloud/ocis-glauth/pkg/config"
|
||||
"github.com/owncloud/ocis-glauth/pkg/version"
|
||||
"github.com/owncloud/ocis-pkg/v2/service/debug"
|
||||
)
|
||||
|
||||
// Server initializes the debug service and server.
|
||||
func Server(opts ...Option) (*http.Server, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
return debug.NewService(
|
||||
debug.Logger(options.Logger),
|
||||
debug.Name("glauth"),
|
||||
debug.Version(version.String),
|
||||
debug.Address(options.Config.Debug.Addr),
|
||||
debug.Token(options.Config.Debug.Token),
|
||||
debug.Pprof(options.Config.Debug.Pprof),
|
||||
debug.Zpages(options.Config.Debug.Zpages),
|
||||
debug.Health(health(options.Config)),
|
||||
debug.Ready(ready(options.Config)),
|
||||
), nil
|
||||
}
|
||||
|
||||
// health implements the health check.
|
||||
func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
// TODO(tboerger): check if services are up and running
|
||||
|
||||
io.WriteString(w, http.StatusText(http.StatusOK))
|
||||
}
|
||||
}
|
||||
|
||||
// ready implements the ready check.
|
||||
func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
// TODO(tboerger): check if services are up and running
|
||||
|
||||
io.WriteString(w, http.StatusText(http.StatusOK))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
package glauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/glauth/glauth/pkg/config"
|
||||
"github.com/glauth/glauth/pkg/handler"
|
||||
"github.com/glauth/glauth/pkg/stats"
|
||||
ber "github.com/nmcclain/asn1-ber"
|
||||
"github.com/nmcclain/ldap"
|
||||
accounts "github.com/owncloud/ocis-accounts/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
)
|
||||
|
||||
type queryType string
|
||||
|
||||
const (
|
||||
usersQuery queryType = "users"
|
||||
groupsQuery queryType = "groups"
|
||||
)
|
||||
|
||||
type ocisHandler struct {
|
||||
as accounts.AccountsService
|
||||
gs accounts.GroupsService
|
||||
log log.Logger
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
func (h ocisHandler) Bind(bindDN, bindSimplePw string, conn net.Conn) (ldap.LDAPResultCode, error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.cfg.Backend.BaseDN)
|
||||
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Bind request")
|
||||
|
||||
stats.Frontend.Add("bind_reqs", 1)
|
||||
|
||||
// parse the bindDN - ensure that the bindDN ends with the BaseDN
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
h.log.Error().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("BindDN not part of our BaseDN")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
parts := strings.Split(strings.TrimSuffix(bindDN, baseDN), ",")
|
||||
if len(parts) > 2 {
|
||||
h.log.Error().
|
||||
Str("binddn", bindDN).
|
||||
Int("numparts", len(parts)).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("BindDN should have only one or two parts")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
userName := strings.TrimPrefix(parts[0], "cn=")
|
||||
|
||||
// check password
|
||||
res, err := h.as.ListAccounts(context.TODO(), &accounts.ListAccountsRequest{
|
||||
//Query: fmt.Sprintf("username eq '%s'", username),
|
||||
// TODO this allows lookung up users when you know the username using basic auth
|
||||
// adding the password to the query is an option but sending the sover the wira a la scim seems ugly
|
||||
// but to set passwords our accounts need it anyway
|
||||
Query: fmt.Sprintf("login eq '%s' and password eq '%s'", userName, bindSimplePw),
|
||||
})
|
||||
if err != nil || len(res.Accounts) == 0 {
|
||||
h.log.Error().
|
||||
Str("username", userName).
|
||||
Str("binddn", bindDN).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Login failed")
|
||||
return ldap.LDAPResultInvalidCredentials, nil
|
||||
}
|
||||
|
||||
stats.Frontend.Add("bind_successes", 1)
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Bind success")
|
||||
return ldap.LDAPResultSuccess, nil
|
||||
}
|
||||
|
||||
func (h ocisHandler) Search(bindDN string, searchReq ldap.SearchRequest, conn net.Conn) (ldap.ServerSearchResult, error) {
|
||||
bindDN = strings.ToLower(bindDN)
|
||||
baseDN := strings.ToLower("," + h.cfg.Backend.BaseDN)
|
||||
searchBaseDN := strings.ToLower(searchReq.BaseDN)
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Search request")
|
||||
stats.Frontend.Add("search_reqs", 1)
|
||||
|
||||
// validate the user is authenticated and has appropriate access
|
||||
if len(bindDN) < 1 {
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultInsufficientAccessRights,
|
||||
}, fmt.Errorf("search error: Anonymous BindDN not allowed %s", bindDN)
|
||||
}
|
||||
if !strings.HasSuffix(bindDN, baseDN) {
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultInsufficientAccessRights,
|
||||
}, fmt.Errorf("search error: BindDN %s not in our BaseDN %s", bindDN, h.cfg.Backend.BaseDN)
|
||||
}
|
||||
if !strings.HasSuffix(searchBaseDN, h.cfg.Backend.BaseDN) {
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultInsufficientAccessRights,
|
||||
}, fmt.Errorf("search error: search BaseDN %s is not in our BaseDN %s", searchBaseDN, h.cfg.Backend.BaseDN)
|
||||
}
|
||||
|
||||
var qtype queryType = ""
|
||||
query := ""
|
||||
var code ldap.LDAPResultCode
|
||||
var err error
|
||||
if searchReq.Filter == "(&)" { // see Absolute True and False Filters in https://tools.ietf.org/html/rfc4526#section-2
|
||||
query = ""
|
||||
} else {
|
||||
var cf *ber.Packet
|
||||
cf, err = ldap.CompileFilter(searchReq.Filter)
|
||||
if err != nil {
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("could not compile filter")
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultOperationsError,
|
||||
}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
qtype, query, code, err = parseFilter(cf)
|
||||
if err != nil {
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: code,
|
||||
}, fmt.Errorf("Search Error: error parsing filter: %s", searchReq.Filter)
|
||||
}
|
||||
|
||||
// check if the searchBaseDN already has a username and add it to the query
|
||||
parts := strings.Split(strings.TrimSuffix(searchBaseDN, baseDN), ",")
|
||||
if len(parts) > 0 && strings.HasPrefix(parts[0], "cn=") {
|
||||
if len(query) > 0 {
|
||||
query += " AND "
|
||||
}
|
||||
query += fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(strings.TrimPrefix(parts[0], "cn=")))
|
||||
}
|
||||
}
|
||||
|
||||
entries := []*ldap.Entry{}
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Str("qtype", string(qtype)).
|
||||
Str("query", query).
|
||||
Msg("parsed query")
|
||||
switch qtype {
|
||||
case usersQuery:
|
||||
accounts, err := h.as.ListAccounts(context.TODO(), &accounts.ListAccountsRequest{
|
||||
Query: query,
|
||||
})
|
||||
if err != nil {
|
||||
h.log.Error().
|
||||
Err(err).
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Str("query", query).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Could not list accounts")
|
||||
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultOperationsError,
|
||||
}, errors.New("search error: error listing users")
|
||||
}
|
||||
entries = append(entries, h.mapAccounts(accounts.Accounts)...)
|
||||
case groupsQuery:
|
||||
groups, err := h.gs.ListGroups(context.TODO(), &accounts.ListGroupsRequest{
|
||||
Query: query,
|
||||
})
|
||||
if err != nil {
|
||||
h.log.Error().
|
||||
Err(err).
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Str("query", query).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("Could not list groups")
|
||||
|
||||
return ldap.ServerSearchResult{
|
||||
ResultCode: ldap.LDAPResultOperationsError,
|
||||
}, errors.New("search error: error listing groups")
|
||||
}
|
||||
entries = append(entries, h.mapGroups(groups.Groups)...)
|
||||
}
|
||||
|
||||
stats.Frontend.Add("search_successes", 1)
|
||||
h.log.Debug().
|
||||
Str("binddn", bindDN).
|
||||
Str("basedn", h.cfg.Backend.BaseDN).
|
||||
Str("filter", searchReq.Filter).
|
||||
Interface("src", conn.RemoteAddr()).
|
||||
Msg("AP: Search OK")
|
||||
|
||||
return ldap.ServerSearchResult{
|
||||
Entries: entries,
|
||||
Referrals: []string{},
|
||||
Controls: []ldap.Control{},
|
||||
ResultCode: ldap.LDAPResultSuccess,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func attribute(name string, values ...string) *ldap.EntryAttribute {
|
||||
return &ldap.EntryAttribute{
|
||||
Name: name,
|
||||
Values: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (h ocisHandler) mapAccounts(accounts []*accounts.Account) []*ldap.Entry {
|
||||
var entries []*ldap.Entry
|
||||
for i := range accounts {
|
||||
attrs := []*ldap.EntryAttribute{
|
||||
attribute("objectClass", "posixAccount", "inetOrgPerson", "organizationalPerson", "Person", "top"),
|
||||
attribute("cn", accounts[i].PreferredName),
|
||||
attribute("uid", accounts[i].PreferredName),
|
||||
attribute("sn", accounts[i].PreferredName),
|
||||
attribute("homeDirectory", ""),
|
||||
attribute("ownCloudUUID", accounts[i].Id), // see https://github.com/butonic/owncloud-ldap-schema/blob/master/owncloud.schema#L28-L34
|
||||
}
|
||||
if accounts[i].DisplayName != "" {
|
||||
attrs = append(attrs, attribute("displayName", accounts[i].DisplayName))
|
||||
}
|
||||
if accounts[i].Mail != "" {
|
||||
attrs = append(attrs, attribute("mail", accounts[i].Mail))
|
||||
}
|
||||
if accounts[i].UidNumber != 0 { // TODO no root?
|
||||
attrs = append(attrs, attribute("uidnumber", strconv.FormatInt(accounts[i].UidNumber, 10)))
|
||||
}
|
||||
if accounts[i].GidNumber != 0 {
|
||||
attrs = append(attrs, attribute("gidnumber", strconv.FormatInt(accounts[i].GidNumber, 10)))
|
||||
}
|
||||
if accounts[i].Description != "" {
|
||||
attrs = append(attrs, attribute("description", accounts[i].Description))
|
||||
}
|
||||
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s",
|
||||
h.cfg.Backend.NameFormat,
|
||||
accounts[i].PreferredName,
|
||||
h.cfg.Backend.GroupFormat,
|
||||
"users",
|
||||
h.cfg.Backend.BaseDN,
|
||||
)
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func (h ocisHandler) mapGroups(groups []*accounts.Group) []*ldap.Entry {
|
||||
var entries []*ldap.Entry
|
||||
for i := range groups {
|
||||
attrs := []*ldap.EntryAttribute{
|
||||
attribute("objectClass", "posixGroup", "groupOfNames", "top"),
|
||||
attribute("cn", groups[i].OnPremisesSamAccountName),
|
||||
attribute("ownCloudUUID", groups[i].Id), // see https://github.com/butonic/owncloud-ldap-schema/blob/master/owncloud.schema#L28-L34
|
||||
}
|
||||
if groups[i].DisplayName != "" {
|
||||
attrs = append(attrs, attribute("displayName", groups[i].DisplayName))
|
||||
}
|
||||
if groups[i].GidNumber != 0 {
|
||||
attrs = append(attrs, attribute("gidnumber", strconv.FormatInt(groups[i].GidNumber, 10)))
|
||||
}
|
||||
if groups[i].Description != "" {
|
||||
attrs = append(attrs, attribute("description", groups[i].Description))
|
||||
}
|
||||
|
||||
dn := fmt.Sprintf("%s=%s,%s=%s,%s",
|
||||
h.cfg.Backend.NameFormat,
|
||||
groups[i].OnPremisesSamAccountName,
|
||||
h.cfg.Backend.GroupFormat,
|
||||
"groups",
|
||||
h.cfg.Backend.BaseDN,
|
||||
)
|
||||
|
||||
memberUids := make([]string, len(groups[i].Members))
|
||||
for j := range groups[i].Members {
|
||||
memberUids[j] = groups[i].Members[j].PreferredName
|
||||
}
|
||||
attrs = append(attrs, attribute("memberuid", memberUids...))
|
||||
entries = append(entries, &ldap.Entry{DN: dn, Attributes: attrs})
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
// LDAP filters might ask for groups and users at the same time, eg.
|
||||
// (|
|
||||
// (&(objectClass=posixaccount)(cn=einstein))
|
||||
// (&(objectClass=posixgroup)(cn=users))
|
||||
// )
|
||||
|
||||
// (&(objectClass=posixaccount)(objectClass=posixgroup))
|
||||
// qtype is one of
|
||||
// "" not determined
|
||||
// "users"
|
||||
// "groups"
|
||||
func parseFilter(f *ber.Packet) (queryType, string, ldap.LDAPResultCode, error) {
|
||||
var qtype queryType
|
||||
var q string
|
||||
var code ldap.LDAPResultCode
|
||||
var err error
|
||||
switch ldap.FilterMap[f.Tag] {
|
||||
case "Equality Match":
|
||||
if len(f.Children) != 2 {
|
||||
return "", "", ldap.LDAPResultOperationsError, errors.New("equality match must have exactly two children")
|
||||
}
|
||||
attribute := strings.ToLower(f.Children[0].Value.(string))
|
||||
value := f.Children[1].Value.(string)
|
||||
|
||||
// replace attributes
|
||||
switch attribute {
|
||||
case "objectclass":
|
||||
switch strings.ToLower(value) {
|
||||
case "posixaccount", "shadowaccount", "users", "person", "inetorgperson", "organizationalperson":
|
||||
qtype = usersQuery
|
||||
case "posixgroup", "groups":
|
||||
qtype = groupsQuery
|
||||
default:
|
||||
qtype = ""
|
||||
}
|
||||
case "ownclouduuid":
|
||||
q = fmt.Sprintf("id eq '%s'", escapeValue(value))
|
||||
case "cn", "uid":
|
||||
// on_premises_sam_account_name is indexed using the lowercase analyzer in ocis-accounts
|
||||
// TODO use "tolower(on_premises_sam_account_name) eq '%s'" to be clear about the case insensitive comparison
|
||||
q = fmt.Sprintf("on_premises_sam_account_name eq '%s'", escapeValue(value))
|
||||
case "mail":
|
||||
q = fmt.Sprintf("mail eq '%s'", escapeValue(value))
|
||||
case "displayname":
|
||||
q = fmt.Sprintf("display_name eq '%s'", escapeValue(value))
|
||||
case "uidnumber":
|
||||
if i, err := strconv.ParseUint(value, 10, 64); err != nil {
|
||||
code = ldap.LDAPResultInvalidAttributeSyntax
|
||||
} else {
|
||||
q = fmt.Sprintf("uid_number eq %d", i)
|
||||
}
|
||||
case "gidnumber":
|
||||
if i, err := strconv.ParseUint(value, 10, 64); err != nil {
|
||||
code = ldap.LDAPResultInvalidAttributeSyntax
|
||||
} else {
|
||||
q = fmt.Sprintf("gid_number eq %d", i)
|
||||
}
|
||||
case "description":
|
||||
q = fmt.Sprintf("description eq '%s'", escapeValue(value))
|
||||
default:
|
||||
code = ldap.LDAPResultUndefinedAttributeType
|
||||
err = fmt.Errorf("unrecognized assertion type '%s' in filter item", attribute)
|
||||
}
|
||||
return qtype, q, code, err
|
||||
case "Substrings":
|
||||
if len(f.Children) != 2 {
|
||||
return "", "", ldap.LDAPResultOperationsError, errors.New("substrings filter must have exactly two children")
|
||||
}
|
||||
attribute := strings.ToLower(f.Children[0].Value.(string))
|
||||
if len(f.Children[1].Children) != 1 {
|
||||
return "", "", ldap.LDAPResultUnwillingToPerform, fmt.Errorf("substrings filter only supports prefix match")
|
||||
}
|
||||
value := f.Children[1].Children[0].Value.(string)
|
||||
|
||||
// replace attributes
|
||||
switch attribute {
|
||||
case "objectclass":
|
||||
switch strings.ToLower(value) {
|
||||
case "posixaccount", "shadowaccount", "users", "person", "inetorgperson", "organizationalperson":
|
||||
qtype = usersQuery
|
||||
case "posixgroup", "groups":
|
||||
qtype = groupsQuery
|
||||
default:
|
||||
qtype = ""
|
||||
}
|
||||
case "ownclouduuid":
|
||||
q = fmt.Sprintf("startswith(id,'%s')", escapeValue(value))
|
||||
case "cn", "uid":
|
||||
// on_premises_sam_account_name is indexed using the lowercase analyzer in ocis-accounts
|
||||
// TODO use "tolower(on_premises_sam_account_name) eq '%s'" to be clear about the case insensitive comparison
|
||||
q = fmt.Sprintf("startswith(on_premises_sam_account_name,'%s')", escapeValue(value))
|
||||
case "mail":
|
||||
q = fmt.Sprintf("startswith(mail,'%s')", escapeValue(value))
|
||||
case "displayname":
|
||||
q = fmt.Sprintf("startswith(display_name,'%s')", escapeValue(value))
|
||||
case "description":
|
||||
q = fmt.Sprintf("startswith(description,'%s')", escapeValue(value))
|
||||
default:
|
||||
code = ldap.LDAPResultUndefinedAttributeType
|
||||
err = fmt.Errorf("unrecognized assertion type '%s' in filter item", attribute)
|
||||
}
|
||||
return qtype, q, code, err
|
||||
case "And", "Or":
|
||||
subQueries := []string{}
|
||||
for i := range f.Children {
|
||||
var subQuery string
|
||||
var qt queryType
|
||||
qt, subQuery, code, err = parseFilter(f.Children[i])
|
||||
if err != nil {
|
||||
return "", "", code, err
|
||||
}
|
||||
if qtype == "" {
|
||||
qtype = qt
|
||||
} else if qt != "" && qt != qtype {
|
||||
return "", "", ldap.LDAPResultUnwillingToPerform, fmt.Errorf("mixing user and group filters not supported")
|
||||
}
|
||||
if subQuery != "" {
|
||||
subQueries = append(subQueries, subQuery)
|
||||
}
|
||||
}
|
||||
return qtype, strings.Join(subQueries, " "+strings.ToLower(ldap.FilterMap[f.Tag])+" "), ldap.LDAPResultSuccess, nil
|
||||
case "Not":
|
||||
if len(f.Children) != 1 {
|
||||
return "", "", ldap.LDAPResultOperationsError, errors.New("not filter match must have exactly one child")
|
||||
}
|
||||
qtype, subQuery, code, err := parseFilter(f.Children[0])
|
||||
if err != nil {
|
||||
return "", "", code, err
|
||||
}
|
||||
if subQuery != "" {
|
||||
q = fmt.Sprintf("not %s", subQuery)
|
||||
}
|
||||
return qtype, q, code, nil
|
||||
}
|
||||
return qtype, q, ldap.LDAPResultUnwillingToPerform, fmt.Errorf("%s filter not implemented", ldap.FilterMap[f.Tag])
|
||||
}
|
||||
|
||||
// escapeValue escapes all special characters in the value
|
||||
func escapeValue(value string) string {
|
||||
return strings.ReplaceAll(value, "'", "''")
|
||||
}
|
||||
|
||||
func (h ocisHandler) Close(boundDN string, conn net.Conn) error {
|
||||
stats.Frontend.Add("closes", 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewOCISHandler implements a glauth backend with ocis-accounts as tdhe datasource
|
||||
func NewOCISHandler(opts ...Option) handler.Handler {
|
||||
options := newOptions(opts...)
|
||||
|
||||
handler := ocisHandler{
|
||||
log: options.Logger,
|
||||
cfg: options.Config,
|
||||
as: options.AccountsService,
|
||||
gs: options.GroupsService,
|
||||
}
|
||||
return handler
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package glauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/glauth/glauth/pkg/config"
|
||||
accounts "github.com/owncloud/ocis-accounts/pkg/proto/v0"
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Options defines the available options for this package.
|
||||
type Options struct {
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
AccountsService accounts.AccountsService
|
||||
GroupsService accounts.GroupsService
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
// Logger provides a function to set the logger option.
|
||||
func Logger(val log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = val
|
||||
}
|
||||
}
|
||||
|
||||
// Context provides a function to set the context option.
|
||||
func Context(val context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = val
|
||||
}
|
||||
}
|
||||
|
||||
// Config provides a function to set the config option.
|
||||
func Config(val *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = val
|
||||
}
|
||||
}
|
||||
|
||||
// AccountsService provides an AccountsService client to set the AccountsService option.
|
||||
func AccountsService(val accounts.AccountsService) Option {
|
||||
return func(o *Options) {
|
||||
o.AccountsService = val
|
||||
}
|
||||
}
|
||||
|
||||
// GroupsService provides an GroupsService client to set the GroupsService option.
|
||||
func GroupsService(val accounts.GroupsService) Option {
|
||||
return func(o *Options) {
|
||||
o.GroupsService = val
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package glauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/GeertJohan/yubigo"
|
||||
"github.com/glauth/glauth/pkg/config"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/nmcclain/ldap"
|
||||
"github.com/owncloud/ocis-glauth/pkg/mlogr"
|
||||
)
|
||||
|
||||
// LdapSvc holds the ldap server struct
|
||||
type LdapSvc struct {
|
||||
log logr.Logger
|
||||
c *config.Config
|
||||
yubiAuth *yubigo.YubiAuth
|
||||
l *ldap.Server
|
||||
}
|
||||
|
||||
// Server initializes the debug service and server.
|
||||
func Server(opts ...Option) (*LdapSvc, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
s := LdapSvc{
|
||||
log: mlogr.New(&options.Logger),
|
||||
c: options.Config,
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
if len(s.c.YubikeyClientID) > 0 && len(s.c.YubikeySecret) > 0 {
|
||||
s.yubiAuth, err = yubigo.NewYubiAuth(s.c.YubikeyClientID, s.c.YubikeySecret)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New("yubikey auth failed")
|
||||
}
|
||||
}
|
||||
|
||||
// configure the backend
|
||||
s.l = ldap.NewServer()
|
||||
s.l.EnforceLDAP = true
|
||||
h := NewOCISHandler(
|
||||
AccountsService(options.AccountsService),
|
||||
GroupsService(options.GroupsService),
|
||||
Logger(options.Logger),
|
||||
Config(s.c),
|
||||
)
|
||||
s.l.BindFunc("", h)
|
||||
s.l.SearchFunc("", h)
|
||||
s.l.CloseFunc("", h)
|
||||
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
// ListenAndServe listens on the TCP network address s.c.LDAP.Listen
|
||||
func (s *LdapSvc) ListenAndServe() error {
|
||||
s.log.V(3).Info("LDAP server listening", "address", s.c.LDAP.Listen)
|
||||
return s.l.ListenAndServe(s.c.LDAP.Listen)
|
||||
}
|
||||
|
||||
// ListenAndServeTLS listens on the TCP network address s.c.LDAPS.Listen
|
||||
func (s *LdapSvc) ListenAndServeTLS() error {
|
||||
s.log.V(3).Info("LDAPS server listening", "address", s.c.LDAPS.Listen)
|
||||
return s.l.ListenAndServeTLS(
|
||||
s.c.LDAPS.Listen,
|
||||
s.c.LDAPS.Cert,
|
||||
s.c.LDAPS.Key,
|
||||
)
|
||||
}
|
||||
|
||||
// Shutdown ends listeners by sending true to the ldap serves quit channel
|
||||
func (s *LdapSvc) Shutdown() {
|
||||
s.l.Quit <- true
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// String gets defined by the build system.
|
||||
String = "0.0.0"
|
||||
|
||||
// Date indicates the build date.
|
||||
Date = "00000000"
|
||||
)
|
||||
|
||||
// Compiled returns the compile time of this service.
|
||||
func Compiled() time.Time {
|
||||
t, _ := time.Parse("20060102", Date)
|
||||
return t
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# backend
|
||||
-r '^(cmd|pkg)/.*\.go$' -R '^node_modules/' -s -- sh -c 'make bin/ocis-glauth-debug && bin/ocis-glauth-debug --log-level debug server --debug-pprof --debug-zpages'
|
||||
@@ -0,0 +1,8 @@
|
||||
// +build tools
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/UnnoTed/fileb0x"
|
||||
_ "github.com/restic/calens"
|
||||
)
|
||||
Reference in New Issue
Block a user