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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions spnego/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
id: spnego
---

# SPNEGO Kerberos Authentication Middleware for Fiber

![Release](https://img.shields.io/github/v/tag/gofiber/contrib?filter=spnego*)
[![Discord](https://img.shields.io/discord/704680098577514527?style=flat&label=%F0%9F%92%AC%20discord&color=00ACD7)](https://gofiber.io/discord)
![Test](https://github.com/gofiber/contrib/workflows/Test%20spnego/badge.svg)

This middleware provides SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) authentication for [Fiber](https://github.com/gofiber/fiber) applications, enabling Kerberos authentication for HTTP requests and inspired by [gokrb5](https://github.com/jcmturner/gokrb5)

[中文版本](README.zh-CN.md)

## Features

- Kerberos authentication via SPNEGO mechanism
- Flexible keytab lookup system
- Support for dynamic keytab retrieval from various sources
- Integration with Fiber context for authenticated identity storage
- Configurable logging

## Version Compatibility

This middleware is available in two versions to support different Fiber releases:

- **v2**: Compatible with Fiber v2
- **v3**: Compatible with Fiber v3

## Installation

```bash
# For Fiber v3
go get github.com/gofiber/contrib/spnego/v3
Copy link
Member

Choose a reason for hiding this comment

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

v2: github.com/gofiber/contrib/v2/spnego
v3: github.com/gofiber/contrib/v3/spnego

You can arrange it so that the packet itself can also have major versions in the future.
future : github.com/gofiber/contrib/v3/spnego/v2

Of course, the go.mod would have to be in the subfolders for that.

Copy link
Member

Choose a reason for hiding this comment

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

@jarod2011 We are currently working on this change and plan to use the prefix.
Can you please adjust it accordingly so that it fits into the scheme?

Copy link
Author

Choose a reason for hiding this comment

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

Hi @ReneWerner87 ,

Thanks for your feedback!

To make sure I understand correctly and to align with the new scheme: should I split this PR into two?

One for the Fiber v3 compatibility, which would be merged into the v3-beta branch.

And another one for the Fiber v2 compatibility, which would be merged into the v2 branch.

Please let me know if this is the right approach. I'm happy to adjust accordingly.

Thanks!


# For Fiber v2
go get github.com/gofiber/contrib/spnego/v2
```

## Usage

### For Fiber v3

```go
package main

import (
"fmt"
"time"

"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v3 "github.com/gofiber/contrib/spnego/v3"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
)

func main() {
app := fiber.New()

// Create a configuration with a keytab lookup function
// For testing, you can create a mock keytab file using utils.NewMockKeytab
// In production, use a real keytab file
keytabLookup, err := spnego.NewKeytabFileLookupFunc("/path/to/keytab/file.keytab")
if err != nil {
log.Fatalf("Failed to create keytab lookup function: %v", err)
}

// Create the middleware
authMiddleware, err := v3.NewSpnegoKrb5AuthenticateMiddleware(spnego.Config{
KeytabLookup: keytabLookup,
})
if err != nil {
log.Fatalf("Failed to create middleware: %v", err)
}

// Apply the middleware to protected routes
app.Use("/protected", authMiddleware)

// Access authenticated identity
app.Get("/protected/resource", func(c fiber.Ctx) error {
identity, ok := spnego.GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.SendString(fmt.Sprintf("Hello, %s!", identity.UserName()))
})

app.Listen(":3000")
}
```

### For Fiber v2

```go
package main

import (
"fmt"
"log"
"os"

"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v2 "github.com/gofiber/contrib/spnego/v2"
"github.com/gofiber/fiber/v2"
)

func main() {
app := fiber.New()

// Create a configuration with a keytab lookup function
// For testing, you can create a mock keytab file using utils.NewMockKeytab
// In production, use a real keytab file
keytabLookup, err := spnego.NewKeytabFileLookupFunc("/path/to/keytab/file.keytab")
if err != nil {
log.Fatalf("Failed to create keytab lookup function: %v", err)
}

// Create the middleware
authMiddleware, err := v2.NewSpnegoKrb5AuthenticateMiddleware(spnego.Config{
KeytabLookup: keytabLookup,
// Optional: Set a custom logger
Log: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds),
})
if err != nil {
log.Fatalf("Failed to create middleware: %v", err)
}

// Apply the middleware to protected routes
app.Use("/protected", authMiddleware)

// Access authenticated identity
app.Get("/protected/resource", func(c *fiber.Ctx) error {
identity, ok := spnego.GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.SendString(fmt.Sprintf("Hello, %s!", identity.UserName()))
})

app.Listen(":3000")
}
```

## Dynamic Keytab Lookup

The middleware is designed with extensibility in mind, allowing keytab retrieval from various sources beyond static files:

```go
// Example: Retrieve keytab from a database
func dbKeytabLookup() (*keytab.Keytab, error) {
// Your database lookup logic here
// ...
return keytabFromDatabase, nil
}

// Example: Retrieve keytab from a remote service
func remoteKeytabLookup() (*keytab.Keytab, error) {
// Your remote service call logic here
// ...
return keytabFromRemote, nil
}
```

## API Reference

### `NewSpnegoKrb5AuthenticateMiddleware(cfg spnego.Config) (fiber.Handler, error)`

Creates a new SPNEGO authentication middleware.

### `GetAuthenticatedIdentityFromContext(ctx fiber.Ctx) (goidentity.Identity, bool)`

Retrieves the authenticated identity from the Fiber context.

### `NewKeytabFileLookupFunc(keytabFiles ...string) (KeytabLookupFunc, error)`

Creates a new KeytabLookupFunc that loads keytab files.
Comment on lines +176 to +178
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

API reference inconsistency.

The API reference mentions NewKeytabFileLookupFunc as if it's in the version packages, but it's actually in the config package.

-### `NewKeytabFileLookupFunc(keytabFiles ...string) (KeytabLookupFunc, error)`
+### `config.NewKeytabFileLookupFunc(keytabFiles ...string) (config.KeytabLookupFunc, error)`

-Creates a new KeytabLookupFunc that loads keytab files.
+Creates a new KeytabLookupFunc that loads and merges keytab files.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### `NewKeytabFileLookupFunc(keytabFiles ...string) (KeytabLookupFunc, error)`
Creates a new KeytabLookupFunc that loads keytab files.
### `config.NewKeytabFileLookupFunc(keytabFiles ...string) (config.KeytabLookupFunc, error)`
Creates a new KeytabLookupFunc that loads and merges keytab files.
🤖 Prompt for AI Agents
In spnego/README.md around lines 175 to 177, the API reference incorrectly
states that NewKeytabFileLookupFunc is part of the version packages, but it is
actually located in the config package. Update the documentation to correctly
indicate that NewKeytabFileLookupFunc belongs to the config package to ensure
accurate API referencing.


## Configuration

The `Config` struct supports the following fields:

- `KeytabLookup`: A function that retrieves the keytab (required)
- `Log`: The logger used for middleware logging (optional, defaults to Fiber's default logger)

## Requirements

- Go 1.21 or higher
- For v3: Fiber v3
- For v2: Fiber v2
- Kerberos infrastructure

## Notes

- Ensure your Kerberos infrastructure is properly configured
- The middleware handles the SPNEGO negotiation process
- Authenticated identities are stored in the Fiber context using `spnego.contextKeyOfIdentity`
190 changes: 190 additions & 0 deletions spnego/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# SPNEGO Kerberos 认证中间件 for Fiber

[English Version](README.md)

该中间件为Fiber应用提供SPNEGO(简单受保护GSSAPI协商机制)认证,使HTTP请求能够使用Kerberos认证。

## 功能特点

- 通过SPNEGO机制实现Kerberos认证
- 灵活的keytab查找系统
- 支持从各种来源动态检索keytab
- 与Fiber上下文集成用于存储认证身份
- 可配置日志

## 版本兼容性

该中间件提供两个版本以支持不同的Fiber版本:

- **v2**:兼容Fiber v2
- **v3**:兼容Fiber v3

## 安装

```bash
# 对于Fiber v3
go get github.com/gofiber/contrib/spnego/v3

# 对于Fiber v2
go get github.com/gofiber/contrib/spnego/v2
```

## 使用方法

### 对于Fiber v3

```go
package main

import (
"fmt"
"time"

"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v3 "github.com/gofiber/contrib/spnego/v3"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
)
Comment on lines +39 to +48
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused import from the v3 example.

utils isn’t used in the v3 snippet, causing a compile error if copied verbatim. Keep the comment about utils.NewMockKeytab or show a working usage; at minimum drop the unused import.

 import (
     "fmt"
     "time"
 
     "github.com/gofiber/contrib/spnego"
-    "github.com/gofiber/contrib/spnego/utils"
     v3 "github.com/gofiber/contrib/spnego/v3"
     "github.com/gofiber/fiber/v3"
     "github.com/gofiber/fiber/v3/log"
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import (
"fmt"
"time"
"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v3 "github.com/gofiber/contrib/spnego/v3"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
)
import (
"fmt"
"time"
"github.com/gofiber/contrib/spnego"
v3 "github.com/gofiber/contrib/spnego/v3"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/log"
)
🤖 Prompt for AI Agents
In spnego/README.zh-CN.md around lines 39 to 48, the v3 example imports
"github.com/gofiber/contrib/spnego/utils" but never uses it which causes compile
errors when copying the snippet; remove the unused utils import or alternatively
demonstrate its use (e.g., call utils.NewMockKeytab in the example) so the
import is actually referenced; update the import block to omit utils if you
choose to keep the snippet minimal, or add a short usage line showing how to
construct the mock keytab and pass it to the v3 config.


func main() {
app := fiber.New()

// 创建带有keytab查找函数的配置
// 测试环境下,您可以使用utils.NewMockKeytab创建模拟keytab文件
// 生产环境下,请使用真实的keytab文件
keytabLookup, err := spnego.NewKeytabFileLookupFunc("/path/to/keytab/file.keytab")
if err != nil {
log.Fatalf("创建keytab查找函数失败: %v", err)
}

// 创建中间件
authMiddleware, err := v3.NewSpnegoKrb5AuthenticateMiddleware(spnego.Config{
KeytabLookup: keytabLookup,
})
if err != nil {
log.Fatalf("创建中间件失败: %v", err)
}

// 将中间件应用于受保护的路由
app.Use("/protected", authMiddleware)

// 访问认证身份
app.Get("/protected/resource", func(c fiber.Ctx) error {
identity, ok := spnego.GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("未授权")
}
return c.SendString(fmt.Sprintf("你好, %s!", identity.UserName()))
})

app.Listen(":3000")
}
```

### 对于Fiber v2

```go
package main

import (
"fmt"
"log"
"os"

"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v2 "github.com/gofiber/contrib/spnego/v2"
"github.com/gofiber/fiber/v2"
)

Comment on lines +90 to +100
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused import from the v2 example.

Same unused utils import in the v2 snippet.

 import (
     "fmt"
     "log"
     "os"
 
     "github.com/gofiber/contrib/spnego"
-    "github.com/gofiber/contrib/spnego/utils"
     v2 "github.com/gofiber/contrib/spnego/v2"
     "github.com/gofiber/fiber/v2"
 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import (
"fmt"
"log"
"os"
"github.com/gofiber/contrib/spnego"
"github.com/gofiber/contrib/spnego/utils"
v2 "github.com/gofiber/contrib/spnego/v2"
"github.com/gofiber/fiber/v2"
)
import (
"fmt"
"log"
"os"
"github.com/gofiber/contrib/spnego"
v2 "github.com/gofiber/contrib/spnego/v2"
"github.com/gofiber/fiber/v2"
)
🤖 Prompt for AI Agents
In spnego/README.zh-CN.md around lines 90 to 100, the v2 example imports an
unused "github.com/gofiber/contrib/spnego/utils" package; remove that unused
import from the import block so only required packages remain (fmt, log, os, v2
"github.com/gofiber/contrib/spnego/v2", and "github.com/gofiber/fiber/v2") to
eliminate the unused-import warning and keep examples accurate.

func main() {
app := fiber.New()

// 创建带有keytab查找函数的配置
// 测试环境下,您可以使用utils.NewMockKeytab创建模拟keytab文件
// 生产环境下,请使用真实的keytab文件
keytabLookup, err := spnego.NewKeytabFileLookupFunc("/path/to/keytab/file.keytab")
if err != nil {
log.Fatalf("创建keytab查找函数失败: %v", err)
}

// 创建中间件
authMiddleware, err := v2.NewSpnegoKrb5AuthenticateMiddleware(spnego.Config{
KeytabLookup: keytabLookup,
// 可选:设置自定义日志器
Log: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds),
})
if err != nil {
log.Fatalf("创建中间件失败: %v", err)
}

// 将中间件应用于受保护的路由
app.Use("/protected", authMiddleware)

// 访问认证身份
app.Get("/protected/resource", func(c *fiber.Ctx) error {
identity, ok := spnego.GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("未授权")
}
return c.SendString(fmt.Sprintf("你好, %s!", identity.UserName()))
})

app.Listen(":3000")
}

## 动态Keytab查找

中间件的设计考虑了扩展性,允许从静态文件以外的各种来源检索keytab:

```go
// 示例:从数据库检索keytab
func dbKeytabLookup() (*keytab.Keytab, error) {
// 您的数据库查找逻辑
// ...
return keytabFromDatabase, nil
}

// 示例:从远程服务检索keytab
func remoteKeytabLookup() (*keytab.Keytab, error) {
// 您的远程服务调用逻辑
// ...
return keytabFromRemote, nil
}
```

## API参考

### `NewSpnegoKrb5AuthenticateMiddleware(cfg spnego.Config) (fiber.Handler, error)`

创建一个新的SPNEGO认证中间件。

### `GetAuthenticatedIdentityFromContext(ctx fiber.Ctx) (goidentity.Identity, bool)`

从Fiber上下文中检索已认证的身份。

### `NewKeytabFileLookupFunc(keytabFiles ...string) (KeytabLookupFunc, error)`

创建一个加载keytab文件的新KeytabLookupFunc。

## 配置

`Config`结构体支持以下字段:

- `KeytabLookup`:检索keytab的函数(必需)
- `Log`:用于中间件日志记录的日志器(可选,默认为Fiber的默认日志器)

## 要求

- Go 1.21或更高版本
- 对于v3:Fiber v3
- 对于v2:Fiber v2
- Kerberos基础设施

## 注意事项

- 确保您的Kerberos基础设施已正确配置
- 中间件处理SPNEGO协商过程
- 已认证的身份使用`spnego.contextKeyOfIdentity`存储在Fiber上下文中
```
Loading