github.com/greenpau/go-authcrunch@v1.1.4/pkg/authn/api_add_user_u2f_token.go (about)

     1  // Copyright 2024 Paul Greenberg greenpau@outlook.com
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package authn
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  
    21  	"github.com/greenpau/go-authcrunch/pkg/authn/enums/operator"
    22  	"github.com/greenpau/go-authcrunch/pkg/ids"
    23  	"github.com/greenpau/go-authcrunch/pkg/requests"
    24  	"github.com/greenpau/go-authcrunch/pkg/tagging"
    25  	"github.com/greenpau/go-authcrunch/pkg/user"
    26  )
    27  
    28  // AddUserUniSecFactorToken adds U2F token to user identity.
    29  func (p *Portal) AddUserUniSecFactorToken(
    30  	ctx context.Context,
    31  	w http.ResponseWriter,
    32  	r *http.Request,
    33  	rr *requests.Request,
    34  	parsedUser *user.User,
    35  	resp map[string]interface{},
    36  	usr *user.User,
    37  	backend ids.IdentityStore,
    38  	bodyData map[string]interface{}) error {
    39  
    40  	var tokenTitle, tokenDescription string
    41  	var tokenLabels []string = []string{}
    42  	var tokenTags []tagging.Tag = []tagging.Tag{}
    43  
    44  	// Validate inputs.
    45  	if v, exists := bodyData["webauthn_register"]; exists {
    46  		rr.WebAuthn.Register = v.(string)
    47  	} else {
    48  		resp["message"] = "Profile API did not find webauthn_register in the request payload"
    49  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    50  	}
    51  	if v, exists := bodyData["webauthn_challenge"]; exists {
    52  		rr.WebAuthn.Challenge = v.(string)
    53  	} else {
    54  		resp["message"] = "Profile API did not find webauthn_challenge in the request payload"
    55  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    56  	}
    57  	if v, exists := bodyData["title"]; exists {
    58  		tokenTitle = v.(string)
    59  	} else {
    60  		resp["message"] = "Profile API did not find title in the request payload"
    61  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    62  	}
    63  	if v, exists := bodyData["description"]; exists {
    64  		tokenDescription = v.(string)
    65  	} else {
    66  		resp["message"] = "Profile API did not find description in the request payload"
    67  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    68  	}
    69  	if extractedTokenTags, err := tagging.ExtractTags(bodyData); err == nil {
    70  		for _, extractedTokenTag := range extractedTokenTags {
    71  			tokenTags = append(tokenTags, *extractedTokenTag)
    72  		}
    73  	} else {
    74  		resp["message"] = "Profile API find malformed tags in the request payload"
    75  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    76  	}
    77  	if extractedTokenLabels, err := tagging.ExtractLabels(bodyData); err == nil {
    78  		tokenLabels = extractedTokenLabels
    79  	} else {
    80  		resp["message"] = "Profile API find malformed tags in the request payload"
    81  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    82  	}
    83  
    84  	// Validate data.
    85  	if !tokenIssuerRegexPattern.MatchString(tokenTitle) {
    86  		resp["message"] = "Profile API found non-compliant token title value"
    87  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    88  	}
    89  	if !tokenDescriptionRegexPattern.MatchString(tokenDescription) && (tokenDescription != "") {
    90  		resp["message"] = "Profile API found non-compliant token description value"
    91  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
    92  	}
    93  
    94  	rr.MfaToken.Type = "u2f"
    95  	rr.MfaToken.Comment = tokenTitle
    96  	rr.MfaToken.Description = tokenDescription
    97  	rr.MfaToken.Tags = tokenTags
    98  	rr.MfaToken.Labels = tokenLabels
    99  
   100  	if err := backend.Request(operator.AddMfaToken, rr); err != nil {
   101  		resp["message"] = "Profile API failed to add token to identity store"
   102  		return handleAPIProfileResponse(w, rr, http.StatusBadRequest, resp)
   103  	}
   104  
   105  	resp["entry"] = "Created"
   106  	return handleAPIProfileResponse(w, rr, http.StatusOK, resp)
   107  }