All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tbk.spring.lnurl.security.wallet.LnurlAuthWalletAuthenticationProvider Maven / Gradle / Ivy

There is a newer version: 0.14.0
Show newest version
package org.tbk.spring.lnurl.security.wallet;

import fr.acinq.bitcoin.ByteVector64;
import fr.acinq.bitcoin.Crypto;
import fr.acinq.bitcoin.PublicKey;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.tbk.lnurl.auth.*;
import org.tbk.spring.lnurl.security.AbstractTokenAuthenticationProvider;
import org.tbk.spring.lnurl.security.LnurlAuthenticationException;

@RequiredArgsConstructor
public class LnurlAuthWalletAuthenticationProvider extends AbstractTokenAuthenticationProvider {

    @NonNull
    private final K1Manager k1Manager;

    @NonNull
    private final LnurlAuthPairingService lnurlAuthPairingService;

    @NonNull
    private final UserDetailsService userDetailsService;

    @Override
    public boolean supports(Class authentication) {
        return LnurlAuthWalletToken.class.isAssignableFrom(authentication);
    }

    @Override
    protected LinkingKey retrieveLinkingKey(Authentication authentication) throws AuthenticationException {
        LnurlAuthWalletToken auth = (LnurlAuthWalletToken) authentication;

        if (auth.isAuthenticated()) {
            throw new LnurlAuthenticationException("Already authenticated.");
        }

        K1 k1 = auth.getK1();

        boolean validK1 = k1Manager.isValid(k1);
        if (!validK1) {
            throw new BadCredentialsException("k1 value has either expired or was not generated by this service.");
        }

        boolean loginVerified = verifyLogin(auth);
        if (!loginVerified) {
            throw new BadCredentialsException("k1 and signature could not be verified.");
        }

        try {
            lnurlAuthPairingService.pairK1WithLinkingKey(k1, auth.getLinkingKey());
        } catch (Exception e) {
            throw new AuthenticationServiceException("Could not pair k1 with linkingKey", e);
        }

        k1Manager.invalidate(k1);

        return auth.getLinkingKey();
    }

    @Override
    protected UserDetails retrieveUser(LinkingKey linkingKey, Authentication authentication) throws AuthenticationException {
        return userDetailsService.loadUserByUsername(linkingKey.toHex());
    }

    @Override
    protected Authentication createSuccessAuthentication(LinkingKey linkingKey, Authentication authentication, UserDetails user) {
        LnurlAuthWalletToken auth = (LnurlAuthWalletToken) authentication;

        LnurlAuthWalletToken newAuth = new LnurlAuthWalletToken(auth.getK1(), auth.getSignature(), linkingKey, user.getAuthorities());
        newAuth.setDetails(user);

        return newAuth;
    }

    private boolean verifyLogin(LnurlAuthWalletToken auth) {
        return verifyLogin(auth.getK1(), auth.getSignature(), auth.getLinkingKey());
    }

    private boolean verifyLogin(K1 k1, Signature signature, LinkingKey linkingKey) {
        byte[] rawK1 = k1.toArray();
        ByteVector64 rawSig = Crypto.der2compact(signature.toArray());
        PublicKey rawKey = PublicKey.fromHex(linkingKey.toHex());

        return Crypto.verifySignature(rawK1, rawSig, rawKey);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy