...

Source file src/edge-infra.dev/pkg/edge/iam/storage/request.go

Documentation: edge-infra.dev/pkg/edge/iam/storage

     1  package storage
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  
     7  	"net/url"
     8  	"time"
     9  
    10  	"github.com/google/uuid"
    11  	"github.com/ory/fosite"
    12  	"github.com/pkg/errors"
    13  
    14  	"edge-infra.dev/pkg/edge/iam/log"
    15  )
    16  
    17  // Request is a concrete implementation of a fosite.Request, extended to
    18  // support the required data for OAuth2 and OpenID.
    19  type Request struct {
    20  	// ID contains the unique request identifier.
    21  	ID string `bson:"id" json:"id" xml:"id"`
    22  	// CreateTime is when the resource was created in seconds from the epoch.
    23  	CreateTime int64 `bson:"createTime" json:"createTime" xml:"createTime"`
    24  	// UpdateTime is the last time the resource was modified in seconds from
    25  	// the epoch.
    26  	UpdateTime int64 `bson:"updateTime" json:"updateTime" xml:"updateTime"`
    27  	// RequestedAt is the time the request was made.
    28  	RequestedAt time.Time `bson:"requestedAt" json:"requestedAt" xml:"requestedAt"`
    29  	// Signature contains a unique session signature.
    30  	Signature string `bson:"signature" json:"signature" xml:"signature"`
    31  	// ClientID contains a link to the Client that was used to authenticate
    32  	// this session.
    33  	ClientID string `bson:"clientId" json:"clientId" xml:"clientId"`
    34  	// UserID contains the subject's unique ID which links back to a stored
    35  	// user account.
    36  	UserID string `bson:"userId" json:"userId" xml:"userId"`
    37  	// Scopes contains the scopes that the user requested.
    38  	RequestedScope fosite.Arguments `bson:"scopes" json:"scopes" xml:"scopes"`
    39  	// GrantedScope contains the list of scopes that the user was actually
    40  	// granted.
    41  	GrantedScope fosite.Arguments `bson:"grantedScopes" json:"grantedScopes" xml:"grantedScopes"`
    42  	// RequestedAudience contains the audience the user requested.
    43  	RequestedAudience fosite.Arguments `bson:"requestedAudience" json:"requestedAudience" xml:"requestedAudience"`
    44  	// GrantedAudience contains the list of audiences the user was actually
    45  	// granted.
    46  	GrantedAudience fosite.Arguments `bson:"grantedAudience" json:"grantedAudience" xml:"grantedAudience"`
    47  	// Form contains the url values that were passed in to authenticate the
    48  	// user's client session.
    49  	Form url.Values `bson:"formData" json:"formData" xml:"formData"`
    50  	// Active is specifically used for Authorize Code flow revocation.
    51  	Active bool `bson:"active" json:"active" xml:"active"`
    52  	// Session contains the session data. The underlying structure differs
    53  	// based on OAuth strategy, so we need to store it as binary-encoded JSON.
    54  	// Otherwise, it can be stored but not unmarshalled back into a
    55  	// fosite.Session.
    56  	//Session []byte `bson:"sessionData" json:"sessionData" xml:"sessionData"`
    57  
    58  	Session json.RawMessage `bson:"sessionData" json:"sessionData" xml:"sessionData"`
    59  }
    60  
    61  // NewRequest returns a new Redis Store request object.
    62  func NewRequest() Request {
    63  	return Request{
    64  		ID:             uuid.New().String(),
    65  		RequestedAt:    time.Now(),
    66  		Signature:      "",
    67  		ClientID:       "",
    68  		UserID:         "",
    69  		RequestedScope: fosite.Arguments{},
    70  		GrantedScope:   fosite.Arguments{},
    71  		Form:           make(url.Values),
    72  		Active:         true,
    73  		Session:        nil,
    74  	}
    75  }
    76  
    77  type MaskedRequest struct {
    78  	// ID contains the unique request identifier.
    79  	ID string `bson:"id" json:"id" xml:"id"`
    80  	// CreateTime is when the resource was created in seconds from the epoch.
    81  	CreateTime int64 `bson:"createTime" json:"createTime" xml:"createTime"`
    82  	// UpdateTime is the last time the resource was modified in seconds from
    83  	// the epoch.
    84  	UpdateTime int64 `bson:"updateTime" json:"updateTime" xml:"updateTime"`
    85  	// RequestedAt is the time the request was made.
    86  	RequestedAt time.Time `bson:"requestedAt" json:"requestedAt" xml:"requestedAt"`
    87  	// Signature contains a unique session signature.
    88  	Signature string `bson:"signature" json:"signature" xml:"signature"`
    89  	// ClientID contains a link to the Client that was used to authenticate
    90  	// this session.
    91  	ClientID string `bson:"clientId" json:"clientId" xml:"clientId"`
    92  	// UserID contains the subject's unique ID which links back to a stored
    93  	// user account.
    94  	UserID string `bson:"userId" json:"userId" xml:"userId"`
    95  	// Scopes contains the scopes that the user requested.
    96  	RequestedScope fosite.Arguments `bson:"scopes" json:"scopes" xml:"scopes"`
    97  	// GrantedScope contains the list of scopes that the user was actually
    98  	// granted.
    99  	GrantedScope fosite.Arguments `bson:"grantedScopes" json:"grantedScopes" xml:"grantedScopes"`
   100  	// RequestedAudience contains the audience the user requested.
   101  	RequestedAudience fosite.Arguments `bson:"requestedAudience" json:"requestedAudience" xml:"requestedAudience"`
   102  	// GrantedAudience contains the list of audiences the user was actually
   103  	// granted.
   104  	GrantedAudience fosite.Arguments `bson:"grantedAudience" json:"grantedAudience" xml:"grantedAudience"`
   105  	// Active is specifically used for Authorize Code flow revocation.
   106  	Active bool `bson:"active" json:"active" xml:"active"`
   107  	// Session contains the session data. The underlying structure differs
   108  	// based on OAuth strategy, so we need to store it as binary-encoded JSON.
   109  	// Otherwise, it can be stored but not unmarshalled back into a
   110  	// fosite.Session.
   111  	//Session []byte `bson:"sessionData" json:"sessionData" xml:"sessionData"`
   112  
   113  	Session json.RawMessage `bson:"sessionData" json:"sessionData" xml:"sessionData"`
   114  }
   115  
   116  // ToMaskedRequest returns a masked request for logging purposes
   117  func (r *Request) ToMaskedRequest(_ context.Context) *MaskedRequest {
   118  	masked := &MaskedRequest{
   119  		ID:                r.ID,
   120  		CreateTime:        r.CreateTime,
   121  		UpdateTime:        r.UpdateTime,
   122  		RequestedAt:       r.RequestedAt,
   123  		ClientID:          r.ClientID,
   124  		UserID:            r.UserID,
   125  		RequestedScope:    r.RequestedScope,
   126  		GrantedScope:      r.GrantedScope,
   127  		RequestedAudience: r.RequestedAudience,
   128  		GrantedAudience:   r.GrantedAudience,
   129  		Active:            r.Active,
   130  		Session:           r.Session,
   131  		Signature:         "*",
   132  	}
   133  
   134  	return masked
   135  }
   136  
   137  // ToFositeRequest transforms a Redis request to a fosite.Request
   138  func (r *Request) ToFositeRequest(ctx context.Context, session fosite.Session, iamClient fosite.Client) (*fosite.Request, error) {
   139  	log := log.Get(ctx)
   140  	if session != nil {
   141  		if err := json.Unmarshal(r.Session, session); err != nil {
   142  			return nil, errors.WithStack(err)
   143  		}
   144  	} else {
   145  		log.Info("Got an empty session")
   146  	}
   147  
   148  	req := &fosite.Request{
   149  		ID:                r.ID,
   150  		RequestedAt:       r.RequestedAt,
   151  		Client:            iamClient,
   152  		RequestedScope:    r.RequestedScope,
   153  		GrantedScope:      r.GrantedScope,
   154  		Form:              r.Form,
   155  		Session:           session,
   156  		RequestedAudience: r.RequestedAudience,
   157  		GrantedAudience:   r.GrantedAudience,
   158  	}
   159  
   160  	return req, nil
   161  }
   162  
   163  // ToStorage transforms a fosite.Request to a storage.Request
   164  // Signature is a hash that relates to the underlying request method and may not
   165  // be a strict 'signature', for example, authorization code grant passes in an
   166  // authorization code.
   167  func ToStorage(signature string, r fosite.Requester) Request {
   168  	session, _ := json.Marshal(r.GetSession())
   169  
   170  	return Request{
   171  		ID:                r.GetID(),
   172  		RequestedAt:       r.GetRequestedAt(),
   173  		Signature:         signature,
   174  		ClientID:          r.GetClient().GetID(),
   175  		UserID:            r.GetSession().GetSubject(),
   176  		RequestedScope:    r.GetRequestedScopes(),
   177  		GrantedScope:      r.GetGrantedScopes(),
   178  		RequestedAudience: r.GetRequestedAudience(),
   179  		GrantedAudience:   r.GetGrantedAudience(),
   180  		Form:              r.GetRequestForm(),
   181  		Active:            true,
   182  		Session:           session,
   183  	}
   184  }
   185  
   186  // BarcodeRequest is a request schema to store a barcode session in any of the storage implementations.
   187  // type BarcodeRequest struct {
   188  // 	// Subject is the user this barcode is issued to
   189  // 	Subject string `bson:"subject" json:"subject" xml:"subject"`
   190  // 	// Credential is a unique generated credential for a barcode generation request.
   191  // 	Credential string `bson:"credential" json:"credential" xml:"credential"`
   192  // 	// CreatedAt refers to the timestamp when the barcode is generated as per user request.
   193  // 	CreatedAt time.Time `bson:"createdAt" json:"createdAt" xml:"createdAt"`
   194  // 	// ExpiresIn refers to the duration in seconds for which the barcode would be valid after creation.
   195  // 	ExpiresIn int64 `bson:"expiresIn" json:"expiresIn" xml:"expiresIn"`
   196  // 	// Roles refers to authz roles of a User in BSL
   197  // 	Roles string `bson:"rls" json:"rls,omitempty" xml:"rls"`
   198  // }
   199  
   200  // type BarcodeCodeRequest struct {
   201  // 	// Subject is the user this barcode is issued to
   202  // 	Subject string `bson:"subject" json:"subject" xml:"subject"`
   203  // 	// ClientID is used to make sure that the same client is the one exchanging the code for the actual barcode
   204  // 	ClientID string `bson:"clientId" json:"clientId" xml:"clientId"`
   205  // 	// CreatedAt refers to the timestamp when the barcode is generated as per user request.
   206  // 	CreatedAt time.Time `bson:"createdAt" json:"createdAt" xml:"createdAt"`
   207  // }
   208  
   209  // func (b BarcodeRequest) GetCredential() string {
   210  // 	return b.Credential
   211  // }
   212  
   213  // func (b BarcodeRequest) GetCreatedAt() time.Time {
   214  // 	return b.CreatedAt
   215  // }
   216  
   217  // func (b BarcodeRequest) GetExpiresIn() int64 {
   218  // 	return b.ExpiresIn
   219  // }
   220  
   221  // func (b BarcodeRequest) GetRoles() string {
   222  // 	return b.Roles
   223  // }
   224  
   225  // func (b BarcodeRequest) GetSubject() string {
   226  // 	return b.Subject
   227  // }
   228  
   229  // func (b BarcodeCodeRequest) GetSubject() string {
   230  // 	return b.Subject
   231  // }
   232  
   233  // func (b BarcodeCodeRequest) GetCreatedAt() time.Time {
   234  // 	return b.CreatedAt
   235  // }
   236  
   237  // func (b BarcodeCodeRequest) GetClientID() string {
   238  // 	return b.ClientID
   239  // }
   240  
   241  // type BarcodeRequester interface {
   242  // 	GetCredential() string
   243  // 	GetCreatedAt() time.Time
   244  // 	GetExpiresIn() int64
   245  // 	GetRoles() string
   246  // 	GetSubject() string
   247  // }
   248  
   249  // type BarcodeCodeRequester interface {
   250  // 	GetSubject() string
   251  // 	GetClientID() string
   252  // 	GetCreatedAt() time.Time
   253  // }
   254  

View as plain text